Spring Authorization Server 已登陸 Spring Initializr!

工程技術 | Steve Riesenberg | 2023 年 5 月 24 日 | ...

今天,我很高興地宣佈,你擁有了一項新超能力:使用 Spring Authorization ServerSpring Initializr 上建立應用程式!

沒錯,是時候開始你的 OAuth2 之旅,成為你一直以來註定要成為的英雄了!在這篇文章中,我將解釋如何充分利用你的新超能力,以及在哪裡可以瞭解更多資訊。

什麼是 Spring Authorization Server?

Spring Authorization Server 是一個構建在 Spring Security 之上的開源框架,它允許你建立自己的基於標準的 OAuth2 Authorization Server 或 OpenID Connect Provider。它實現了各種 OAuth2 和 OIDC 相關規範中提供的許多協議端點,讓你能夠更多地關注應用程式和使用者,而減少對流程和規範的關注。由於它位於 Spring Security 之上,因此它也可以用於建立一個認證中心,以便將其他認證協議適配到 OAuth2。

你可以在 參考指南概覽 中瞭解更多關於 Spring Authorization Server 的資訊。

入門

拯救世界免受試圖消滅一切生命的邪惡生物侵害的旅程必須從某個地方開始,而你成為 OAuth2 英雄的旅程也一樣!要開始,請下載這個 示例應用程式 或前往 start.spring.io 並將 OAuth2 Authorization Server 依賴項新增到你的專案中。

然後,在你喜歡的 IDE 中開啟專案,並將以下內容新增到 application.properties

spring.security.oauth2.authorizationserver.client.client-1.registration.client-id=admin-client
# the client secret is "secret" (without quotes)
spring.security.oauth2.authorizationserver.client.client-1.registration.client-secret={bcrypt}$2a$10$jdJGhzsiIqYFpjJiYWMl/eKDOd8vdyQis2aynmFN0dgJ53XvpzzwC
spring.security.oauth2.authorizationserver.client.client-1.registration.client-authentication-methods=client_secret_basic
spring.security.oauth2.authorizationserver.client.client-1.registration.authorization-grant-types=client_credentials
spring.security.oauth2.authorizationserver.client.client-1.registration.scopes=user.read,user.write

或者,你可以將 application.properties 重新命名為 application.yml 並新增以下內容

spring:
  security:
    oauth2:
      authorizationserver:
        client:
          client-1:
            registration:
              client-id: "admin-client"
              # the client secret is "secret" (without quotes)
              client-secret: "{bcrypt}$2a$10$jdJGhzsiIqYFpjJiYWMl/eKDOd8vdyQis2aynmFN0dgJ53XvpzzwC"
              client-authentication-methods: "client_secret_basic"
              authorization-grant-types: "client_credentials"
              scopes: "user.read,user.write"

要啟動應用程式,請執行以下命令

./gradlew bootRun

這將為你提供一個開箱即用、具備以下功能的應用程式

  • 一個使用 Spring Security 保護的基於 Servlet 的 Web 應用程式
  • 一個符合標準的授權伺服器,帶有一個用於獲取 OAuth2 Access Token (JWT) 的 Token 端點
  • 一個生成的記憶體中 RSA 金鑰對,將用於簽名 JWT
  • 一個 JWK-Set 端點1 用於獲取生成的公鑰
  • 一個 OAuth2 Authorization Server Metadata 端點2 用於發現授權伺服器配置
  • 一個 OpenID Connect Provider Configuration 端點3 用於發現 OIDC 提供者配置
  • 一個 OAuth2 Introspection 端點,用於使用不透明令牌或獲取關於令牌(包括 JWT)的資訊
  • 一個 OAuth2 Revocation 端點,用於撤銷重新整理令牌(或不透明訪問令牌)
  • 一個註冊到授權伺服器上的、支援 Client Credentials 流程的、記憶體中的單客戶端(帶預雜湊的金鑰

當然,這不止這些,你可以檢視功能列表獲取完整列表。

獲取訪問令牌

那麼我們能用這個做什麼呢?使用上面的示例,我們將從最容易理解的 Client Credentials 流程開始。我將使用命令列工具 HTTPie 進行演示,你可以在家(或工作時)跟著操作。

執行以下命令

http -f POST :8080/oauth2/token grant_type=client_credentials scope='user.read' -a admin-client:secret

這將產生一個類似以下的響應

{
    "access_token": "eyJraWQiOiJhMWZjM2JhOC0zY2IwLTRkZjAtYTQwNS03ZDhhY2YxYTY4NGIiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJhZG1pbi1jbGllbnQiLCJhdWQiOiJhZG1pbi1jbGllbnQiLCJuYmYiOjE2ODQ1MjYzOTgsInNjb3BlIjpbInVzZXIucmVhZCJdLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODAiLCJleHAiOjE2ODQ1MjY2OTgsImlhdCI6MTY4NDUyNjM5OH0.sHDGoQGDpdBuhvdiIpFeeCtTUeU860FBeV23rS6Zqb8tjq_Pytj_Y4Xl6pBB2R5rTAZdMg0cwLvICVYBz-x-hGz2UbHFtYGmo24byb3iKGqBb2BjtY5mMuYQOdnW_PgUVV4vtElhTYkkN_uET4CZ3zxIhgPEc2Yvtt0-d2lGwXzkDiHb_US1zDSUO36nqs4cesMD-yzy5tVmr1e2c6Klojyv6nFN1edfTn7Ci5GvEeB4lDnQdm3ZJr4fyxSiSrq7T34ghj6fMqYn_-lazpoc-wWPB5I35NM0TkUyDw2e_XobqIm6oXG0tBDujL2SK6P05n5MDKkGhgsQlT_ER9gmqA",
    "expires_in": 299,
    "scope": "user.read",
    "token_type": "Bearer"
}

響應中的 access_token 是一個已簽名的 JWT,可用於向 OAuth2 資源伺服器發起帶 user.read 作用域的認證請求,以訪問受保護資源。換句話說,只需一個 Spring Boot 應用程式和一些屬性,我們就可以輕鬆地鑄造已簽名的 JWT,並開始使用 OAuth2 保護應用程式。當然,使用 Spring Security 設定資源伺服器也同樣簡單,但那將留給你來測試你未知曉的超能力。

內省訪問令牌

為了簡單起見,我們使用 Introspection 端點來測試此令牌。

注意:請記住令牌將在 5 分鐘後過期。

執行以下命令,請務必將實際的 access_token 貼上到示例位置

export TOKEN=eyJraW...
http -f POST :8080/oauth2/introspect token=$TOKEN -a admin-client:secret

這將產生一個類似以下的響應

{
    "active": true,
    "aud": [
        "admin-client"
    ],
    "client_id": "admin-client",
    "exp": 1684526698,
    "iat": 1684526398,
    "iss": "https://:8080",
    "nbf": 1684526398,
    "scope": "user.read",
    "sub": "admin-client",
    "token_type": "Bearer"
}

如果你看到以下響應

{
    "active": false
}

則令牌可能已過期。

如果你想深入一點探索正在發生的事情,可以啟用跟蹤日誌以獲取更多除錯詳細資訊。你還可以將令牌的過期時間縮短到非常短,例如 30 秒,以便更容易獲得一個過期的令牌。

將以下內容新增到你的 application.properties

logging.level.org.springframework.security=trace
spring.security.oauth2.authorizationserver.client.client-1.token.access-token-time-to-live=30s

或者如果你正在使用 application.yml,新增以下內容

logging:
  level:
    org.springframework.security: trace

spring:
  security:
    oauth2:
      authorizationserver:
        client:
          client-1:
            registration:
              ...
            token:
              access-token-time-to-live: 30s

然後重啟應用程式,並再次嘗試上述步驟。發出內省請求後,你將看到類似如下的日誌行

FilterChainProxy : Trying to match request against DefaultSecurityFilterChain [...] (1/2)
FilterChainProxy : Securing POST /oauth2/introspect
FilterChainProxy : Invoking DisableEncodeUrlFilter (1/25)
...

有兩件有趣的事情正在發生。在日誌中靠後的幾行,你將看到類似如下的輸出

...
FilterChainProxy                   : Invoking OAuth2ClientAuthenticationFilter (14/25)
ProviderManager                    : Authenticating request with JwtClientAssertionAuthenticationProvider (1/18)
ProviderManager                    : Authenticating request with ClientSecretAuthenticationProvider (2/18)
ClientSecretAuthenticationProvider : Retrieved registered client
ClientSecretAuthenticationProvider : Validated client authentication parameters
ClientSecretAuthenticationProvider : Authenticated client secret
OAuth2ClientAuthenticationFilter   : Set SecurityContextHolder authentication to OAuth2ClientAuthenticationToken
...

這告訴我們客戶端(我們自己的 CLI)透過 ClientSecretAuthenticationProvider 使用 HTTP 基本認證成功進行了身份驗證。這就是我們收到 200 OK 響應的原因,但透過日誌確認令牌內省請求成功就更好了。再往後幾行,你將看到這樣的輸出

...
FilterChainProxy                         : Invoking OAuth2TokenIntrospectionEndpointFilter (22/25)
ProviderManager                          : Authenticating request with OAuth2TokenIntrospectionAuthenticationProvider (1/18)
TokenIntrospectionAuthenticationProvider : Retrieved authorization with token
TokenIntrospectionAuthenticationProvider : Did not introspect token since not active
...

這裡我們看到 OAuth2TokenIntrospectionAuthenticationProvider 正在處理請求,但令牌未啟用。因此,我們可以確認請求是成功的,但令牌已過期。

接下來做什麼?

我們只探索了你新超能力的一小部分!我希望你能記住的主要一點是,現在你可以使用 Spring Initializr 結合 Spring Authorization Server 建立你自己的個人 OAuth2 和 OpenID Connect 練兵場。

當你準備好時,我鼓勵你閱讀參考指南,它包含所有可用功能和配置選項的詳細資訊。我特別推薦如何:使用社交登入進行身份驗證這個指南,作為學習和探索的好方法。

也許瞭解 OAuth2 和 Spring Authorization Server 的最好方法是構建一個包含(至少)三個應用程式的示例 OAuth2 架構

  1. OAuth2 客戶端(使用 OpenID Connect)
  2. OAuth2 資源伺服器
  3. OAuth2 授權伺服器

檢視可用的示例,它們展示了這三個應用程式,並嘗試只使用 Spring Initializr 構建你自己的!一旦你完成了,未來就完全取決於你了!

現在去拯救世界吧!

專案主頁 | GitHub 問題跟蹤器 | ZenHub 看板

註釋


  1. 當應用程式執行時,JWK-Set 端點可在 https://:8080/oauth2/jwks 訪問。
  2. 當應用程式執行時,OAuth2 Authorization Server Metadata 端點可在 https://:8080/.well-known/oauth-authorization-server 訪問。
  3. 當應用程式執行時,OpenID Connect Provider Configuration 端點可在 https://:8080/.well-known/openid-configuration 訪問。

訂閱 Spring 新聞郵件

透過 Spring 新聞郵件保持聯絡

訂閱

搶先一步

VMware 提供培訓和認證,助你加速前進。

瞭解更多

獲得支援

Tanzu Spring 透過一項簡單的訂閱提供 OpenJDK™、Spring 和 Apache Tomcat® 的支援和二進位制檔案。

瞭解更多

即將到來的活動

檢視 Spring 社群的所有即將到來的活動。

檢視全部