2025年9月25日: PostgreSQL 18 釋出!
支援的版本: 當前 (18)
開發版本: devel

32.20. OAuth 支援 #

libpq 實現了一個可選模組,支援 OAuth v2 裝置授權客戶端流程,該流程記錄在 RFC 8628 中。有關如何啟用裝置授權作為內建流程支援的資訊,請參閱 安裝文件

當啟用支援並安裝了可選模組時,如果在認證過程中伺服器 請求令牌(bearer token)libpq 將預設使用內建流程。此流程即使在使用客戶端應用程式的系統沒有可用網頁瀏覽器時也可以使用,例如透過以下方式執行客戶端:SSH.

預設情況下,內建流程將列印一個要訪問的 URL 和一個要在其中輸入的使用者名稱程式碼。

$ psql 'dbname=postgres oauth_issuer=https://example.com oauth_client_id=...'
Visit https://example.com/device and enter the code: ABCD-EFGH

(此提示可能會被 自定義。) 然後使用者將登入其 OAuth 提供商,該提供商將詢問是否允許 libpq 和伺服器代表他們執行操作。在繼續之前,仔細檢查顯示的 URL 和許可權是否符合預期始終是個好主意。不應將許可權授予不受信任的第三方。

客戶端應用程式可以實現自己的流程來自定義與應用程式的互動和整合。有關如何將自定義流程新增到 libpq 的更多資訊,請參閱 第 32.20.1 節

要使 OAuth 客戶端流程可用,連線字串至少必須包含 oauth_issueroauth_client_id。(這些設定由您組織的 OAuth 提供商確定。) 內建流程還需要 OAuth 授權伺服器釋出裝置授權端點。

注意

內建裝置授權流程目前在 Windows 上不受支援。自定義客戶端流程仍然可以實現。

32.20.1. Authdata 鉤子 #

OAuth 流程的行為可以透過客戶端使用以下鉤子 API 進行修改或替換:

PQsetAuthDataHook #

設定 PGauthDataHook,覆蓋 libpq 對其 OAuth 客戶端流程的一個或多個方面的處理。

void PQsetAuthDataHook(PQauthDataHook_type hook);

如果 hookNULL,將重新安裝預設處理程式。否則,應用程式將傳遞一個指向具有以下簽名的回撥函式的指標:

int hook_fn(PGauthData type, PGconn *conn, void *data);

當需要應用程式執行操作時,libpq 將呼叫此函式。type 描述正在進行的請求,conn 是正在進行身份驗證的連線控制代碼,data 指向請求特定的元資料。此指標的內容由 type 確定;有關支援的列表,請參閱 第 32.20.1.1 節

鉤子可以連結在一起,以允許協作和/或回退行為。通常,鉤子實現應檢查傳入的 type (以及可能的請求元資料和/或正在使用的特定 conn 的設定),以決定是否處理特定的 authdata。如果不處理,則應將其委託給鏈中的前一個鉤子 (可透過 PQgetAuthDataHook 檢索)。

成功透過返回一個大於零的整數來表示。返回負整數表示錯誤條件並中止連線嘗試。(零值保留給預設實現)。

PQgetAuthDataHook #

檢索 PGauthDataHook 的當前值。

PQauthDataHook_type PQgetAuthDataHook(void);

在初始化時 (第一次呼叫 PQsetAuthDataHook 之前),此函式將返回 PQdefaultAuthDataHook

32.20.1.1. 鉤子型別 #

定義了以下 PGauthData 型別及其相應的 data 結構:

PQAUTHDATA_PROMPT_OAUTH_DEVICE #

替換內建裝置授權客戶端流程期間的預設使用者提示。data 指向 PGpromptOAuthDevice 的例項。

typedef struct _PGpromptOAuthDevice
{
    const char *verification_uri;   /* verification URI to visit */
    const char *user_code;          /* user code to enter */
    const char *verification_uri_complete;  /* optional combination of URI and
                                             * code, or NULL */
    int         expires_in;         /* seconds until user code expires */
} PGpromptOAuthDevice;

可以 包含libpq 中的 OAuth 裝置授權流程要求終端使用者使用瀏覽器訪問一個 URL,然後輸入一個程式碼,該程式碼允許 libpq 代表他們連線到伺服器。預設提示只是將 verification_uriuser_code 列印到標準錯誤。替換實現可以使用任何首選方法顯示此資訊,例如使用 GUI。

僅在內建裝置授權流程期間呼叫此回撥。如果應用程式安裝了 自定義 OAuth 流程,或者 libpq 未內建支援內建流程,則不會使用此 authdata 型別。

如果提供了非 NULL 的 verification_uri_complete,則可以選擇將其用於非文字驗證 (例如,透過顯示二維碼)。在這種情況下,仍應將 URL 和使用者名稱程式碼顯示給終端使用者,因為程式碼將由提供商手動確認,並且 URL 允許使用者繼續,即使他們無法使用非文字方法。有關更多資訊,請參閱 RFC 8628 的第 3.3.1 節。

PQAUTHDATA_OAUTH_BEARER_TOKEN #

新增自定義流程實現,替換內建流程 (如果已 安裝)。鉤子應該直接返回當前使用者/發行方/範圍組合的 Bearer 令牌 (如果可用且不阻塞),或者設定一個非同步回撥來檢索它。

data 指向 PGoauthBearerRequest 的例項,該例項應由實現填充。

typedef struct PGoauthBearerRequest
{
    /* Hook inputs (constant across all calls) */
    const char *openid_configuration; /* OIDC discovery URL */
    const char *scope;                /* required scope(s), or NULL */

    /* Hook outputs */

    /* Callback implementing a custom asynchronous OAuth flow. */
    PostgresPollingStatusType (*async) (PGconn *conn,
                                        struct PGoauthBearerRequest *request,
                                        SOCKTYPE *altsock);

    /* Callback to clean up custom allocations. */
    void        (*cleanup) (PGconn *conn, struct PGoauthBearerRequest *request);

    char       *token;   /* acquired Bearer token */
    void       *user;    /* hook-defined allocated data */
} PGoauthBearerRequest;

libpq 向鉤子提供兩類資訊:openid_configuration 包含描述授權伺服器支援的流程的 OAuth 發現文件的 URL,scope 包含訪問伺服器所需的 OAuth 範圍的空格分隔列表 (可能為空)。兩者都可能為 NULL,表示資訊無法發現。(在這種情況下,實現可能能夠使用其他預配置的知識來建立需求,或者它們可以選擇失敗)。

鉤子的最終輸出是 token,它必須指向一個有效的 Bearer 令牌,以便在連線中使用。(此令牌應由 oauth_issuer 發行,幷包含請求的範圍,否則連線將被伺服器的驗證器模組拒絕。) 分配的令牌字串在 libpq 完成連線之前必須保持有效;鉤子應設定一個 cleanup 回撥,當 libpq 不再需要它時將被呼叫。

如果實現無法在鉤子首次呼叫期間立即生成 token,它應該設定 async 回撥來處理與授權伺服器的非阻塞通訊。[16] 當鉤子返回後,將呼叫此回撥來立即啟動流程。當回撥無法在不阻塞的情況下取得進一步進展時,它應該在設定 *pgsocket 為將標記為可讀/可寫以實現再次進度檔案描述符之後,返回 PGRES_POLLING_READINGPGRES_POLLING_WRITING。(然後透過 PQsocket() 將此描述符提供給頂級輪詢迴圈)。當流程完成且 token 已設定時,返回 PGRES_POLLING_OK,或返回 PGRES_POLLING_FAILED 來指示失敗。

實現可能希望儲存額外的資料以在 asynccleanup 回撥之間進行管理。user 指標就是為此目的提供的;libpq 不會觸及其內容,並且應用程式可以根據需要使用它。(記住在令牌清理期間釋放任何分配)。

32.20.2. 除錯和開發者設定 #

透過設定環境變數 PGOAUTHDEBUG=UNSAFE 可以啟用“危險除錯模式”。此功能僅為方便本地開發和測試而提供。它執行了許多您不希望生產系統執行的操作:

  • 允許在 OAuth 提供商交換期間使用未加密的 HTTP。

  • 允許使用 PGOAUTHCAFILE 環境變數完全替換系統的受信任 CA 列表。

  • 在 OAuth 流程期間將 HTTP 流量 (包含多個關鍵秘密) 列印到標準錯誤。

  • 允許使用零秒重試間隔,這可能導致客戶端忙等待並浪費 CPU。

警告

請勿與第三方共享 OAuth 流程流量的輸出。它包含可用於攻擊您的客戶端和伺服器的秘密。



[16]PQAUTHDATA_OAUTH_BEARER_TOKEN 鉤子回撥期間執行阻塞操作會干擾非阻塞連線 API (如 PQconnectPoll),並阻止併發連線取得進展。僅使用同步連線原語 (如 PQconnectdb) 的應用程式可以在鉤子期間同步檢索令牌,而不是實現 async 回撥,但它們將僅限於一次一個連線。

提交更正

如果您在文件中發現任何不正確、與您使用該功能的實際經驗不符或需要進一步說明的內容,請使用 此表單 報告文件問題。