我们目前有多个Spring Boot应用程序使用服务帐户连接到其他服务。直到现在,我们在RestTemplate上使用OAuth2ClientContext的AccessTokenRequest来放置服务帐户的用户和密码,并使用返回的OAuth令牌连接到其他服务。
[现在,我们正在使用Spring Boot 5.2构建一个新应用程序,并且由于现在应该使用新的Spring Security OAuth,因此不再使用单独的OAuth库,我们还想用WebClient代替RestTemplate解决方案作为RestTemplate在不久的将来也会被弃用。我尝试了几种检索令牌的方法,但是找不到可行的解决方案。
我发现了类似于Spring Security 5 Replacement for OAuth2RestTemplate中提到的设置,但是没有办法在WebClient中放入用户名和密码。我发现其他使用ClientRegistrationRepository而不是ReactiveClientRegistrationRepository的方法,其中一些方法实际上具有将用户名和密码放入AuthorizedClientManager中的选项(例如How to re-initialize password grant in Spring security 5.2 OAuth),该实例化过滤器时将其作为参数,但是总以某种方式我总是会结束不管我在application.yaml中放置了什么属性,都找不到找不到ClientRegistrationRepository的Bean的消息(这可能不起作用,因为该应用程序是MVC应用程序而不是WebFlux应用程序?)
[我知道我需要将authorization-grant-type设置为'password',但是已经有人在问如何使它正常工作(Spring Security 5.2.1 + spring-security-oauth2 + WebClient: how to use password grant-type),但该问题尚无答案。
所以...他们是否不赞成使用用户名和密码来检索令牌并使用该令牌连接到Spring Security 5.2中的另一个服务的简单方法?如果是的话,现在应该使用什么?
是,RestTemplate和OAuthRestTemplate均已弃用。 WebClient开箱即用地支持OAuth。您不需要做任何特殊的事情或自己添加任何标题。实际上,这是非常琐碎的。
创建一个公开WebClient bean的配置类,请确保将客户端存储库作为参数。在该方法中,您将存储库传递给过滤器函数:
@Bean
public WebClient webClient(ReactiveClientRegistrationRepository clientRegistrations) {
return WebClient.builder().filter(filterFunction(clientRegistrations))
.baseUrl(String.format("http://%s:8080", getHostName()))
.build();
}
private ServerOAuth2AuthorizedClientExchangeFilterFunction filterFunction(ReactiveClientRegistrationRepository clientRegistrations) {
ServerOAuth2AuthorizedClientExchangeFilterFunction filterFunction = new ServerOAuth2AuthorizedClientExchangeFilterFunction(clientRegistrations, new UnAuthenticatedServerOAuth2AuthorizedClientRepository());
filterFunction.setDefaultClientRegistrationId("myKey");
return filterFunction;
}
注意:在过滤器功能中,将“ myKey”替换为与application.properties中的以下属性结构匹配的名称(用您的名称替换属性路径中的myKey:]
spring.security.oauth2.client.registration.myKey.authorization-grant-type=password
spring.security.oauth2.client.registration.myKey.client-id=xxx
spring.security.oauth2.client.registration.myKey.client-secret=xxx
spring.security.oauth2.client.provider.myKey.token-uri=http://localhost:8080/oauth/token
Aaaannddd ....您完成了!还内置了OAuth令牌刷新。
嗯,事实证明有点不同。关于我链接的最后一个SO问题的评论,要求作者使用PasswordOAuth2AuthorizedClientProvider中的调试功能来查看发生了什么/错误。因此,我也开始调试,并使用您提供的设置为4个登录类型提供了4个提供程序,但在这4个登录类型中,不是使用PasswordReactiveOAuth2AuthorizedProvider,也不是ClientCredentialsReactiveOAuth2AuthorizedProvider或RefreshTokenReactiveOAuth2AuthorizedProvider之一,但是AuthorizationCodeReactiveOAuth2AuthorizedProvider当authorization-grant-type设置为password时,这很奇怪。对我来说,这似乎是个虫子...
无论如何,我从rigon找到了另一个SO问题,它的问题与我的有所不同,但是很接近:Create route in Spring Cloud Gateway with OAuth2 Resource Owner Password grant type,他提供了我可以使用的代码,因为与该代码库一起使用的Provider实际上是PasswordReactiveOAuth2AuthorizedClientProvider
最后,我只需要在yaml文件中输入3个项目:客户端ID(以前将client_id用作AccessTokenRequest的属性),授权授予类型和令牌uri除此之外,我还从rigon提供的代码中复制了WebClient和ReactiveOAuth2AuthorizedClientManager设置,并将配置文件中的用户名和密码放入设置中(我将单独的contextAttributesMapper遗漏了,因为我只需要直接在地图中提供2个上下文参数即可)。