我现在想从spring-security-oauth迁移到spring-security,但是我找不到任何方法。我进行了很多搜索,所能找到的都是有关提供OAuth端点的示例。
我当前的OAuth2RestTemplate有点复杂,因为受帖子here的启发,oauth服务器未使用标准的身份识别方式。
这是我的OAuth2RestTemplate:
fun createOAuthRestTemplate(resourceDetails: OAuth2ProtectedResourceDetails): OAuth2RestTemplate {
val clientCredentialsAccessTokenProvider = ClientCredentialsAccessTokenProvider()
clientCredentialsAccessTokenProvider.setAuthenticationHandler(<myClientAuthenticationHandler extends ClientAuthenticationHandler>))
clientCredentialsAccessTokenProvider.setRequestFactory(requestFactory)
val oauthTemplate = OAuth2RestTemplate(resourceDetails)
oauthTemplate.setAccessTokenProvider(clientCredentialsAccessTokenProvider)
return oauthTemplate
}
[spring migration guide不幸的是,它仅提及RestTemplate,但对我没有多大帮助,但没有详细介绍。
[...]
A Simplified RestTemplate and WebClient
Spring Security OAuth extends RestTemplate, introducing OAuth2RestTemplate.
This class needs to be instantiated and exposed as a @Bean.
Spring Security chooses to favor composition and instead exposes an
OAuth2AuthorizedClientService, which is useful for creating RestTemplate interceptors
[...]
我的问题现在是:如何使用spring-security在rest模板中获得相同的功能?
带有Spring Security 5和RestTemplate的OAuth 2.0
Spring Security 5.2没有对RestTemplate
的直接支持,但是它具有简化工作的bean。如果可能的话,建议使用use WebClient
,而不是WebClient
。
但是,如果您需要使用RestTemplate
,则首先要创建一个RestTemplate
:
OAuth2AuthorizedClientManager
此管理器bean是您要让拦截器为您协商的授予类型的类型做出决定的地方。它类似于您帖子中的@Bean
OAuth2AuthorizedClientManager authorizeClientManager(
ClientRegistrationRepository clients,
OAuth2AuthorizedClientRepository authorizedClients) {
DefaultOAuth2AuthorizedClientManager manager =
new DefaultOAuth2AuthorizedClientManager(clients, authorizedClients);
OAuth2AuthorizedClientProvider authorizedClientProvider =
OAuth2AuthorizedClientProviderBuilder.builder()
.clientCredentials()
.build();
manager.setAuthorizedClientProvider(authorizedClientProvider);
return manager;
}
。
第二,您需要创建一个ClientCredentialsAccessTokenProvider
拦截器。它将要求管理器为其获取令牌,然后将该令牌添加到RestTemplate
标头中:
Authorization
在Spring Security 5中,每个客户端由一个注册ID表示。注册ID代替@Component
public class OAuth2AuthorizedClientInterceptor implements ClientHttpRequestInterceptor {
OAuth2AuthorizedClientManager manager;
public OAuth2AuthorizedClientInterceptor(OAuth2AuthorizedClientManager manager) {
this.manager = manager;
}
public ClientHttpResponse intercept(
HttpRequest request, byte[] body, ClientHttpRequestExecution execution)
throws IOException {
OAuth2AuthorizeRequest authorizeRequest =
OAuth2AuthorizeRequest.withClientRegistrationId("foo-client").build();
OAuth2AuthorizedClient authorizedClient =
this.manager.authorize(authorizedRequest);
HttpHeaders headers = httpRequest.getHeaders();
headers.setBearerAuth(authorizedClient.getAccessToken().getValue());
return execution.execute(request, body);
}
}
。
最后,您可以将拦截器添加到foo-client
:
RestTemplate
JWT客户端身份验证
关于您提到的帖子,它正在执行JWT以进行客户端身份验证。对于这种支持,您将需要配置@Bean
public RestTemplate rest(OAuth2AuthorizedClientInterceptor interceptor) {
RestTemplate rest = new RestTemplate();
rest.getInterceptors().add(interceptor);
return rest;
}
。这将是您在第一步中构建的管理器的一部分:
DefaultClientCredentialsTokenResponseClient
@Bean
OAuth2AuthorizedClientManager authorizeClientManager(
ClientRegistrationRepository clients,
OAuth2AuthorizedClientRepository authorizedClients) {
DefaultOAuth2AuthorizedClientManager manager =
new DefaultOAuth2AuthorizedClientManager(clients, authorizedClients);
DefaultClientCredentialsAccessTokenResponseClient tokenClient =
new DefaultClientCredentialsAccessTokenResponseClient();
tokenClient.setRequestEntityConverter(fooConverter);
OAuth2AuthorizedClientProvider authorizedClientProvider =
OAuth2AuthorizedClientProviderBuilder.builder()
.clientCredentials()
.accessTokenResponseClient(tokenClient)
.build();
manager.setAuthorizedClientProvider(authorizedClientProvider);
return manager;
}
是您指定用于创建适当的fooConverter
实例的任何转换器。类似于:
RequestEntity
此设置器,// ...
tokenClient.setRequestEntityConverter(grantRequest -> {
ClientRegistration client = grantRequest.getClientRegistration();
// ... formulate JWT
// ... create `RequestEntity`, including `Authorization` header
// that includes JWT as the bearer token
});
与旧项目中的setRequestEntityConverter
功能等效。