繁體中文(香港)
  • custom JWT
  • JWT claims
  • authorization
  • authentication
  • OAuth 2.0
  • Logto

透過 Logto 為 JWT 訪問令牌添加自定義聲明以提升授權

在本文中,我們將介紹如何使用 Logto 的自定義 JWT 聲明功能,通過一個實際示例來提高授權的靈活性和服務提供商的性能。

Darcy Ye
Darcy Ye
Developer

在先前的文章中,我們提到越來越多的系統正在使用 JWT 格式的訪問令牌進行用戶身份驗證和訪問控制。這樣做的一個重要原因是,JWT 可以包含一些有用的信息,例如用戶角色和權限。這些信息可以幫助我們在服務器和客戶端之間傳遞用戶身份信息,從而實現用戶身份驗證和訪問控制。

通常,JWT 中包含的信息由身份驗證服務器決定。根據 OAuth 2.0 協議,JWT 通常包含 sub(subject)、aud(audience)和 exp(expiration time)等字段,這些字段通常被稱為聲明。這些聲明可以幫助驗證訪問令牌的有效性。

然而,使用 JWT 進行驗證的場景無數,常見的 JWT 聲明往往無法滿足用戶需求。人們常常想,既然 JWT 可以包含一些信息,那我們可不可以添加一些信息來讓授權更容易呢?

答案是肯定的,我們可以為 JWT 添加自定義聲明,例如當前用戶的範圍和訂閱級別。通過這種方式,我們可以在客戶端和服務端之間(這裡指提供各種不同服務的服務器,也稱為服務提供商)傳遞用戶身份信息,以實現用戶身份驗證和訪問控制。

關於標準的 JWT 聲明,請參考 RFC7519。作為支持身份驗證和授權的解決方案,Logto 在此基礎上擴展了資源和範圍聲明,以支持標準的 RBAC。雖然 Logto 的 RBAC 實現是標準的,但在適應所有使用場景方面並不簡單和靈活。

基於此,Logto 推出了自定義 JWT 聲明的新功能,允許用戶自定義附加的 JWT 聲明,以便能夠更靈活地實現用戶身份驗證和訪問控制。

Logto自定義JWT聲明如何運作?

你可以通過點擊側欄中的“JWT 聲明”按鈕來到自定義 JWT 列表頁。

custom-jwt-listing-page

讓我們從為最終用戶添加自定義聲明開始。

在左側的編輯器中,你可以自定義你的 getCustomJwtClaims 函數。此方法有三個輸入參數:tokendataenvVariables

  • token 是根據當前用戶的憑證和你的系統配置獲取的原始訪問令牌負載,以及用戶在 Logto 中的訪問相關信息
  • data 是 Logto 中關於用戶的所有信息,包括所有用戶的角色、社交登錄身份、單一登錄身份、組織成員身份等。
  • envVariables 是你在 Logto 為當前用戶訪問令牌使用場景配置的環境變量,例如所需外部 API 的 API key(s) 等。
details-page-user-data

右側的卡片可以展開以顯示相應參數的介紹,你也可以在這裡為當前場景設置環境變量。

details-page-user-test

閱讀完右側所有卡片的介紹後,你可以切換到測試模式,在這裡你可以編輯測試數據並使用編輯過的測試數據來檢查你在左側代碼編輯器中編寫的腳本行為是否符合你的預期。

這是當最終用戶向 Logto 發起認證請求並最終獲得 Logto 返回的 JWT 格式訪問令牌時,getCustomJwtClaims 函數的執行過程的序列圖。

如果沒有啟用自定義 JWT 功能,圖中的步驟 3 將被跳過,步驟 2 結束後將直接執行步驟 4。此時,Logto 將假定 getCustomJwtClaims 的返回值為一個空對象,然後繼續進行後續步驟。

使用自定義 JWT 聲明提升授權:一個實際示例

在上一節中,我們介紹了 Logto 自定義 JWT 的工作原理。在這一部分,我們將向你展示如何通過一個實際例子使用 Logto 自定義 JWT 聲明來提高授權的靈活性和服務提供商的性能。

場景設置

約翰的團隊開發了一個 AI 助理應用程序,允許用戶與 AI 機器人對話以獲取各種服務。

AI 機器人服務分為免費和付費服務。免費服務包括特別機票推薦,而付費服務包括股票預測。

AI 助理應用使用 Logto 來管理所有用戶,用戶分為三種:免費用戶、預付費用戶和高級用戶。免費用戶只能使用免費服務,預付費用戶可以使用所有服務(按使用收費),而高級用戶可以使用所有服務(但有速率限制以防止惡意使用)。

此外,AI 助理應用使用 Stripe 來管理用戶付款,並擁有自己的日誌服務來記錄用戶操作日誌。

Logto 配置

我們首先為 AI 助理應用服務創建 API 資源並創建兩個範圍,recommend:flightpredict:stock

ai-assistant-app-resource

然後我們創建兩個 rolesfree-userpaid-user,並分配相應的範圍:

  • recommend:flight 範圍分配給 free-user 角色。
  • recommend:flightpredict:stock 範圍分配給 paid-user 角色。
free-user-role
paid-user-role

最後,我們創建三個用戶,free-userprepaid-userpremium-user,並分配相應的角色:

  • free-user 角色分配給用戶 free-user
  • paid-user 角色分配給用戶 prepaid-userpremium-user
assign-free-user-role
assign-paid-user-role

如圖所示,為了實現上述場景所需的授權信息,我們希望在 JWT 中包含當前登錄用戶的 rolesbalancenumOfCallsToday 信息。在 AI 助理應用中驗證訪問令牌時,這些信息可以用來快速進行權限驗證。

test-custom-jwt-claims

配置 envVariables 後,我們實現了 getCustomJwtClaims 函數並單擊“運行測試”按鈕查看基於當前測試數據的附加 JWT 聲明結果。

由於我們尚未為 data.user.roles 配置測試數據,因此結果中顯示的 roles 為空數組。

檢查自定義 JWT 功能是否生效

根據上述 Logto 配置,我們在測試中得到了相應的結果。接下來,我們將使用 Logto 提供的示例應用來驗證我們的自定義 JWT 是否有效。在Logto SDKs找到你熟悉的 SDK 並根據文檔和相應的 GitHub repo 部署一個示例應用。

根據我們上述描述的配置,以 React SDK 為例,我們需要在 LogtoConfig 中更新相應配置:

在模擬 AI 助理應用的示例應用中簽入用戶 free_user 後,我們可以通過查看 JWT 訪問令牌的負載部分看到我們添加的 rolesbalancenumOfCallsTodayisPaidUserisPremiumUser 信息。

sample-app-access-token-preview-free

balancenumOfCallsTodayisPaidUserisPremiumUser 的值與先前測試一致,而 roles["free-user"]。這是因為在實際的最終用戶登錄過程中,我們將獲取用戶的所有可訪問數據並進行相應處理。

sample-app-access-token-preview-premium

對於高級用戶,我們可以看到 roles["paid-user"],而且 isPaidUserisPremiumUser 均為 true

更新服務提供商授權邏輯

在先前的步驟中,我們根據業務需求將自定義聲明添加到用戶訪問令牌中。接下來,我們可以使用這些聲明快速進行授權驗證。

這里提供了 Logto 在 API 端驗證 JWT 訪問令牌的邏輯。完整的代碼實現可以在GitHub repo中找到:

你可以參考 Logto API 驗證訪問令牌的邏輯,並根據自己的業務邏輯進行自定義。比如在這裡描述的 AI 助理應用場景中,你可以在 verifyBearerTokenFromRequest 函數中添加對自定義聲明的驗證邏輯,如 rolesbalancenumOfCallsTodayisPaidUserisPremiumUser

上述示例是針對影響終端用戶登錄並獲取 JWT 訪問令牌的場景。如果你的用例是機器到機器(M2M),你也可以單獨為 M2M 應用配置自定義 JWT 聲明。

為用戶配置自定義 JWT 不會影響 M2M 應用獲取訪問令牌的結果,反之亦然。

由於M2M連接的普遍性,Logto當前尚未提供M2M應用接受Logto內部數據的 getCustomJwtClaims 方法功能。其他方面,M2M 應用的自定義 JWT 的配置方法與用戶應用相同。本文將不再詳述。你可以使用 Logto 的自定義 JWT 功能開始。

為什麼使用自定義 JWT 聲明?

我們為約翰的 AI 助理應用提供了場景,以及如何使用 Logto 的自定義 JWT 功能來實現更靈活的授權驗證。在此過程中,我們可以看到自定義 JWT 功能的優勢:

  1. 沒有自定義 JWT 功能,當用戶每次檢查權限時,需要請求外部 API(例如你在 getCustomJwtClaims 中所做的)。對於提供此 API 的服務提供商,這可能會增加額外的負擔。有了自定義 JWT 功能,這些信息可以直接放入 JWT 中,減少頻繁調用外部 API。
  2. 對於服務提供商,自定義 JWT 功能可以幫助他們更快地驗證用戶權限,特別是當客戶端頻繁調用服務提供商時,提高服務性能。
  3. 自定義 JWT 功能可以幫助你快速實現業務所需的附加授權信息,這些信息可以在客戶端和服務提供商之間以安全的方式傳遞,因為 JWT 是自包含的,可以加密,難以偽造。

同時,由於 getCustomJwtClaims 在每次用戶需要 Logto 簽發訪問令牌時執行,有必要避免執行過於複雜的邏輯和高帶寬要求的外部 API 請求。否則,最終用戶可能需要等待很長時間才能在登錄過程中得到 getCustomJwtClaims 的結果。如果你的 getCustomJwtClaims 返回一個空對象,我們強烈建議你暫時刪除此配置項,直到你確實需要使用它。

結論

在本文中,Logto 擴展了基本 JWT 訪問令牌並擴展了附加 JWT 聲明的功能,允許用戶根據業務需求將額外的最終用戶信息放入 JWT 訪問令牌中,以便在用戶登錄後,可以快速驗證用戶的權限。

我們提供了約翰的 AI 助理應用場景,並演示了如何使用 Logto 的自定義 JWT 功能來實現更靈活的授權驗證。我們還指出了一些使用自定義 JWT 的關鍵點。結合實際業務場景,用戶可以根據業務需求將各種與用戶相關的信息放入 JWT 訪問令牌中,以便服務提供商能夠快速驗證用戶的權限。