简体   繁体   English

Spring Security 5.2 / WebClient 使用用户名和密码连接到另一个服务的方式是什么?

[英]What's the Spring Security 5.2 / WebClient way of using username & password to connect to another service?

We currently have several Spring Boot applications connecting to other services using a service account.我们目前有几个 Spring Boot 应用程序使用服务帐户连接到其他服务。 Till now we used the AccessTokenRequest of the OAuth2ClientContext on a RestTemplate to put the user and password of the service account in and used the returned OAuth token to connect to the other services.到目前为止,我们在 RestTemplate 上使用 OAuth2ClientContext 的 AccessTokenRequest 将服务帐户的用户和密码放入并使用返回的 OAuth 令牌连接到其他服务。

Right now we're building a new application using Spring Boot 5.2 and as the new Spring Security OAuth should be used now the separate OAuth library has become deprecated, we would also like to replace the RestTemplate solution with a WebClient one as the RestTemplate will become deprecated in the near future as well.现在我们正在使用 Spring Boot 5.2 构建一个新的应用程序,由于现在应该使用新的 Spring Security OAuth,单独的 OAuth 库已被弃用,我们还想用 WebClient 解决方案替换 RestTemplate 解决方案,因为 RestTemplate 将成为在不久的将来也会被弃用。 I've tried several approaches of retrieving the token, but couldn't find a solution that works.我尝试了几种检索令牌的方法,但找不到有效的解决方案。

I found set-ups like the one mentioned on Spring Security 5 Replacement for OAuth2RestTemplate , but no way of putting a username and password inside the WebClient.我找到了类似于Spring Security 5 Replacement for OAuth2RestTemplate 中提到的设置,但无法将用户名和密码放入 WebClient 中。 I found other approaches using a ClientRegistrationRepository instead of a ReactiveClientRegistrationRepository and some of those approaches actually have options (like How to re-initialize password grant in Spring security 5.2 OAuth ) of putting a username and password in an AuthorizedClientManager that gets to be a parameter when instantiating the filter, but somehow I always end up with the message that no Bean of the ClientRegistrationRepository could be found, no matter what properties I put in the application.yaml (maybe this doesn't work because the application is an MVC application instead of a WebFlux one?)我发现其他方法使用 ClientRegistrationRepository 而不是 ReactiveClientRegistrationRepository 并且其中一些方法实际上有选项(例如如何在 Spring security 5.2 OAuth 中重新初始化密码授予)将用户名和密码放入 AuthorizedClientManager 中,当实例化过滤器,但不知何故,我总是以找不到 ClientRegistrationRepository 的 Bean 的消息结束,无论我在 application.yaml 中放入什么属性(也许这不起作用,因为该应用程序是一个 MVC 应用程序而不是一个 WebFlux?)

I know that I need to set the authorization-grant-type to be 'password', but there's already someone else asking how to get that working ( Spring Security 5.2.1 + spring-security-oauth2 + WebClient: how to use password grant-type ) and no answers to that question, yet.我知道我需要将授权授予类型设置为“密码”,但已经有人询问如何使其工作( Spring Security 5.2.1 + spring-security-oauth2 + WebClient:如何使用密码授予-type ) 并且还没有对这个问题的答案。

So ... did they 'deprecate' this easy way of using a username and password to retrieve a token and use that token to connect to another service in Spring Security 5.2?那么......他们是否“弃用”了这种使用用户名和密码检索令牌并使用该令牌连接到 Spring Security 5.2 中的另一个服务的简单方法? And if yes, what should be used now?如果是,现在应该使用什么?

Yes, RestTemplate and OAuthRestTemplate are all deprecated.是的,RestTemplate 和 OAuthRestTemplate 都已弃用。 WebClient supports OAuth out of the box. WebClient 支持开箱即用的 OAuth。 You don't need to do anything special or add any headers yourself.您不需要做任何特别的事情或自己添加任何标题。 It's actually extremely trivial.这实际上非常微不足道。

Create a configuration class that exposes a WebClient bean, make sure you take the client repository as a param.创建一个公开 WebClient bean 的配置类,确保将客户端存储库作为参数。 In the method, you pass the repo into a filter function:在该方法中,您将 repo 传递给过滤器函数:

@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;
    }

NOTE: In the filter function, replace the "myKey" with something that matches the following property structure in application.properties (replace myKey in the property paths with your name):注意:在过滤器函数中,将“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.... you're done! Aaaannddd....你完成了! OAuth token refresh is also built in. OAuth 令牌刷新也是内置的。

Well, it turned out to be a little bit different.嗯,结果有点不同。 A comment on the last SO question I linked requested the author to use debugging in the PasswordOAuth2AuthorizedClientProvider to see what went on / wrong.对我链接的最后一个 SO 问题的评论要求作者在 PasswordOAuth2AuthorizedClientProvider 中使用调试来查看发生了什么/错误。 So I started debugging as well and with the setup you provided there are 4 Providers for 4 login types that are supplied, but out of the 4 it's not the PasswordReactiveOAuth2AuthorizedProvider that's used, and also not the ClientCredentialsReactiveOAuth2AuthorizedProvider or RefreshTokenReactiveOAuth2AuthorizedProvider one, but the AuthorizationCodeReactiveOAuth2AuthorizedProvider is called and that's quite weird when authorization-grant-type is set to password.因此,我也开始调试,并根据您提供的设置为 4 种登录类型提供了 4 个提供程序,但在这 4 个提供程序中,它不是使用的 PasswordReactiveOAuth2AuthorizedProvider,也不是 ClientCredentialsReactiveOAuth2AuthorizedProvider 或 RefreshTokenReactiveOAuth2AuthorizedProvider 之一,但 AuthorizationCodeReactiveOAuthorizedProvider 被称为当授权授予类型设置为密码时,这很奇怪。 That seems like a bug to me ...这对我来说似乎是一个错误......

Anyway, I found another SO question from rigon with a problem a bit different than mine, but close enough: Create route in Spring Cloud Gateway with OAuth2 Resource Owner Password grant type and he provided code I could get working as the Provider used with that codebase is in fact the PasswordReactiveOAuth2AuthorizedClientProvider无论如何,我从rigon 中发现了另一个SO 问题,其问题与我的有点不同,但足够接近: 在Spring Cloud Gateway 中使用OAuth2 资源所有者密码授予类型创建路由,他提供的代码我可以作为与该代码库一起使用的提供者工作实际上是 PasswordReactiveOAuth2AuthorizedClientProvider

In the end I only needed to enter 3 items in the yaml-file: the client-id (with the client_id that used to be put as attribute on the AccessTokenRequest), the authorization-grant-type and the token-uri Besides that I copied the WebClient and ReactiveOAuth2AuthorizedClientManager setup from the code provided by rigon and put the username and password from the configuration file into the settings (I left the seperate contextAttributesMapper out as I only needed to provide 2 context parameters directly into a map).最后我只需要在 yaml-file 中输入 3 项:client-id(使用过去作为属性放在 AccessTokenRequest 上的 client_id),authorization-grant-type 和 token-uri 除此之外我从rigon提供的代码中复制了WebClient和ReactiveOAuth2AuthorizedClientManager设置,并将配置文件中的用户名和密码放入设置中(我离开了单独的contextAttributesMapper,因为我只需要将2个上下文参数直接提供到地图中)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM