Spring 授权服务器现已登陆 Spring Initializr!

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

今天,我很高兴地宣布,您拥有了一项新的超级能力:使用 Spring 授权服务器Spring Initializr 上创建应用程序!

没错,现在是时候开始您的 OAuth2 之旅,并成为您一直以来渴望成为的英雄了!在这篇文章中,我将解释如何充分利用您的新超级能力,以及在哪里可以了解更多信息。

什么是 Spring 授权服务器?

Spring 授权服务器是一个基于 Spring Security 构建的开源框架,它允许您创建自己的基于标准的 OAuth2 授权服务器或 OpenID Connect 提供程序。它实现了各种 OAuth2 和 OIDC 相关规范中提供的许多协议端点,使您能够更多地关注您的应用程序和用户,而无需过多关注流程和规范。由于它建立在 Spring Security 之上,因此它还可以用作身份验证中心,用于将其他身份验证协议适配到 OAuth2。

您可以在 概览(位于 参考指南 中)中了解有关 Spring 授权服务器的更多信息。

入门

拯救世界于试图消灭一切生命的邪恶生物的旅程必须从某个地方开始,您成为 OAuth2 英雄的旅程也一样!要开始,请下载此 示例应用程序 或前往 start.spring.io 并将 OAuth2 授权服务器依赖项添加到您的项目中。

然后,在您喜欢的 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 访问令牌(JWT)
  • 一个生成的内存中 RSA 密钥对,将用于对 JWT 进行签名
  • 一个用于获取生成的公钥的 JWK 集端点1
  • 一个用于发现授权服务器配置的 OAuth2 授权服务器元数据端点2
  • 一个用于发现 OIDC 提供程序配置的 OpenID Connect 提供程序配置端点3
  • 一个 OAuth2 检查端点,用于使用不透明令牌或获取有关令牌的信息(包括 JWT)
  • 一个 OAuth2 吊销端点,用于吊销刷新令牌(或不透明访问令牌)
  • 一个在内存中注册到授权服务器的单个客户端(具有 预散列的密钥),以支持客户端凭据流

当然,还有更多功能,但您可以查看 功能列表 以获取完整列表。

获取访问令牌

那么我们能用它做什么呢?使用上面的示例,我们将从客户端凭据流开始,这是最容易理解的。我将在命令行上使用 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 设置资源服务器同样简单,但我将把它留给您作为对您不知道自己拥有的超级能力的测试。

检查访问令牌

为了简单起见,让我们使用检查端点来测试此令牌。

注意:请记住,令牌将在 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://127.0.0.1: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 授权服务器创建您自己的个人 OAuth2 和 OpenID Connect 游乐场。

准备就绪后,我建议您阅读 参考指南,其中包含有关每个功能和可用配置选项的详细信息。我特别推荐指南 操作方法:使用社交登录进行身份验证,作为学习和探索的好方法。

也许了解 OAuth2 和 Spring 授权服务器的最佳方法是构建一个包含(至少)三个应用程序的示例 OAuth2 架构

  1. OAuth2 客户端(使用 OpenID Connect)
  2. OAuth2 资源服务器
  3. OAuth2 授权服务器

查看可用的 示例,这些示例演示了所有这三个应用程序,并尝试仅使用 Spring Initializr 构建您自己的应用程序!一旦您完成了这些操作,未来就真正掌握在您手中了!

现在,去拯救世界吧!

项目页面 | GitHub 问题 | ZenHub 看板

说明


  1. 当应用程序运行时,JWK 集端点位于 https://127.0.0.1:8080/oauth2/jwks
  2. 当应用程序运行时,OAuth2 授权服务器元数据端点位于 https://127.0.0.1:8080/.well-known/oauth-authorization-server
  3. 当应用程序运行时,OpenID Connect 提供程序配置端点位于 https://127.0.0.1:8080/.well-known/openid-configuration

获取 Spring 新闻通讯

与 Spring 新闻通讯保持联系

订阅

领先一步

VMware 提供培训和认证,以加速您的进步。

了解更多

获取支持

Tanzu Spring 在一个简单的订阅中提供 OpenJDK™、Spring 和 Apache Tomcat® 的支持和二进制文件。

了解更多

即将举行的活动

查看 Spring 社区中所有即将举行的活动。

查看全部