领先一步
VMware 提供培训和认证,助您快速提升。
了解更多我很高兴地宣布,Spring Security 6.3 将支持 OAuth 2.0 令牌交换授权类型 (RFC 8693),该支持已在最新的里程碑版本 (6.3.0-M3) 中提供预览。此支持使能够将令牌交换与 OAuth2 Client 一起使用。类似地,Spring Authorization Server 1.3 也随之发布了服务器端支持,目前可在最新的里程碑版本 (1.3.0-M3) 中进行预览。
Spring Security 的 OAuth2 Client 功能使我们能够轻松地向使用 OAuth2 bearer 令牌保护的 API 发出受保护资源请求。类似地,Spring Security 的 OAuth2 Resource Server 功能使我们能够使用 OAuth2 保护 API。接下来让我们看看如何利用新支持来构建基于令牌交换的 OAuth2 流程。
假设我们有一个名为 user-service
的资源服务器,提供访问用户信息 API。为了向 user-service
发出请求,客户端必须提供访问令牌。假设令牌必须具有 user-service
的 audience (aud
claim)。这在 Spring Boot 配置属性中可能如下所示
spring:
security:
oauth2:
resourceserver:
jwt:
issuer-uri: https://my-auth-server.com
audiences: user-service
现在假设我们想引入一个名为 message-service
的新资源服务器,并从 user-service
中调用它。那么假设这个新服务的令牌必须具有 message-service
的 audience。显然,我们不能在对 message-service
的请求中重用对 user-service
请求中的令牌。但是,我们希望保留原始请求中用户的身份。我们该如何实现这一点?
为了获取 message-service
所需的访问令牌,资源服务器 user-service
必须成为一个客户端,并用现有令牌交换一个保留原始令牌身份(用户)的新令牌。这被称为 “模拟 (impersonation)”,这正是 OAuth 2.0 令牌交换的设计场景。
要启用令牌交换,我们需要将 user-service
配置为既是资源服务器,又是可以使用令牌交换的客户端,如下面的 Spring Boot 配置属性所示
spring:
security:
oauth2:
resourceserver:
jwt:
issuer-uri: https://my-auth-server.com
audiences: user-service
client:
registration:
my-token-exchange-client:
provider: my-auth-server
client-id: token-client
client-secret: token
authorization-grant-type: urn:ietf:params:oauth:grant-type:token-exchange
client-authentication-method: client_secret_basic
scope:
- message.read
provider:
my-auth-server:
issuer-uri: https://my-auth-server.com
我们还需要在 Spring Security 中启用新的授权类型,这可以通过发布以下 bean 来实现
@Bean
public OAuth2AuthorizedClientProvider tokenExchange() {
return new TokenExchangeOAuth2AuthorizedClientProvider();
}
这就是开始使用令牌交换所需的全部内容。但是,如果我们想请求特定的 audience
或 resource
值,则需要在令牌请求中配置额外的参数,如下例所示
@Bean
public OAuth2AuthorizedClientProvider tokenExchange() {
var requestEntityConverter = new TokenExchangeGrantRequestEntityConverter();
requestEntityConverter.addParametersConverter((grantRequest) -> {
var parameters = new LinkedMultiValueMap<String, String>();
parameters.add(OAuth2ParameterNames.AUDIENCE, "message-service");
parameters.add(OAuth2ParameterNames.RESOURCE, "https://example.com/messages");
return parameters;
});
var accessTokenResponseClient = new DefaultTokenExchangeTokenResponseClient();
accessTokenResponseClient.setRequestEntityConverter(requestEntityConverter);
var authorizedClientProvider = new TokenExchangeOAuth2AuthorizedClientProvider();
authorizedClientProvider.setAccessTokenResponseClient(accessTokenResponseClient);
return authorizedClientProvider;
}
完成此配置后,我们可以在一个资源服务器中获取访问令牌,并在向另一个资源服务器发送受保护资源请求时将其用作 Bearer
令牌。默认情况下,传递给资源服务器的 Authorization
头中的原始 bearer 令牌将用于获取新的访问令牌。
提示:有关如何使用此配置获取访问令牌并发出受保护资源请求的更多信息,请参阅参考文档中的 授权客户端功能。
为了完善整个流程,我们来构建一个全新的使用 Spring Authorization Server 的授权服务器应用来支持此流程。
使用 Spring Initializr 并添加 OAuth2 Authorization Server 依赖,我们可以使用以下 Spring Boot 配置属性配置一个功能齐全的授权服务器
spring:
security:
user:
name: sally
password: password
oauth2:
authorizationserver:
client:
test-client:
registration:
client-id: test-client
client-secret: {noop}secret
client-authentication-methods:
- client_secret_basic
authorization-grant-types:
- authorization_code
- refresh_token
scopes:
- user.read
token-client:
registration:
client-id: token-client
client-secret: {noop}token
client-authentication-methods:
- client_secret_basic
authorization-grant-types:
- urn:ietf:params:oauth:grant-type:token-exchange
scopes:
- message.read
与客户端类似,我们可能希望支持令牌交换的特定请求参数,例如 audience
或 resource
,这可以通过发布以下 bean 来实现
@Bean
public OAuth2TokenCustomizer<JwtEncodingContext> accessTokenCustomizer() {
return (context) -> {
if (AuthorizationGrantType.TOKEN_EXCHANGE.equals(context.getAuthorizationGrantType())) {
OAuth2TokenExchangeAuthenticationToken tokenExchangeAuthentication = context.getAuthorizationGrant();
Set<String> resources = tokenExchangeAuthentication.getResources();
// TODO: Validate resource value(s) and map to the
// appropriate audience value(s) if needed...
context.getClaims().audience(...);
}
};
}
完成此配置后,授权服务器将支持带有 OAuth 2.0 令牌请求的可选 resource
参数的令牌交换授权类型,并能够颁发允许资源服务器作为客户端模拟最终用户的令牌。
在这篇博客文章中,我们讨论了令牌交换的“模拟”用例,并探讨了资源服务器(作为客户端)和授权服务器的简单配置。
提示:有关其他示例,包括也受支持的名为“委托 (delegation)”的额外用例示例,请参阅 RFC 8693 的 附录 A。
我希望您和我一样对这项新支持感到兴奋!我鼓励您尝试 Spring Authorization Server 中的 示例,其中包含这篇博客文章的一个工作示例。也请在您自己的项目中尝试 Spring Security 和 Spring Authorization Server 的里程碑版本。我们非常乐意收到您的反馈!