Spring Security 5.2 / WebClient 使用用户名和密码连接到另一个服务的方式是啥?
Posted
技术标签:
【中文标题】Spring Security 5.2 / WebClient 使用用户名和密码连接到另一个服务的方式是啥?【英文标题】:What's the Spring Security 5.2 / WebClient way of using username & password to connect to another service?Spring Security 5.2 / WebClient 使用用户名和密码连接到另一个服务的方式是什么? 【发布时间】:2020-04-30 16:52:19 【问题描述】:我们目前有几个 Spring Boot 应用程序使用服务帐户连接到其他服务。到目前为止,我们使用了 RestTemplate 上的 OAuth2ClientContext 的 AccessTokenRequest 来放入服务帐户的用户和密码,并使用返回的 OAuth 令牌连接到其他服务。
现在我们正在使用 Spring Boot 5.2 构建一个新应用程序,并且由于现在应该使用新的 Spring Security OAuth,因此不推荐使用单独的 OAuth 库,我们还希望将 RestTemplate 解决方案替换为 WebClient 解决方案作为RestTemplate 也将在不久的将来被弃用。我尝试了几种检索令牌的方法,但找不到有效的解决方案。
我发现了类似Spring Security 5 Replacement for OAuth2RestTemplate 中提到的设置,但无法将用户名和密码放入 WebClient 中。 我发现了使用 ClientRegistrationRepository 而不是 ReactiveClientRegistrationRepository 的其他方法,其中一些方法实际上具有将用户名和密码放入 AuthorizedClientManager 中的选项(例如How to re-initialize password grant in Spring security 5.2 OAuth),该选项在实例化过滤器时成为参数,但不知何故我总是结束提示找不到 ClientRegistrationRepository 的 Bean,无论我在 application.yaml 中放置什么属性(也许这不起作用,因为该应用程序是 MVC 应用程序而不是 WebFlux 应用程序?)
我知道我需要将 authorization-grant-type 设置为“密码”,但已经有人询问如何使其正常工作 (Spring Security 5.2.1 + spring-security-oauth2 + WebClient: how to use password grant-type),但该问题尚无答案。
那么......他们是否“弃用”了这种使用用户名和密码来检索令牌并使用该令牌连接到 Spring Security 5.2 中的另一个服务的简单方法?如果是,现在应该使用什么?
【问题讨论】:
【参考方案1】:嗯,结果有点不同。对我链接的最后一个 SO 问题的评论要求作者在 PasswordOAuth2AuthorizedClientProvider 中使用调试来查看发生了什么/错误。因此,我也开始调试,并且根据您提供的设置,提供了 4 种登录类型的 4 个提供程序,但在 4 个提供程序中,它不是使用的 PasswordReactiveOAuth2AuthorizedProvider,也不是 ClientCredentialsReactiveOAuth2AuthorizedProvider 或 RefreshTokenReactiveOAuth2AuthorizedProvider 之一,而是称为 AuthorizationCodeReactiveOAuth2AuthorizedProvider当授权授予类型设置为密码时,这很奇怪。这对我来说似乎是一个错误......
无论如何,我从 rigon 发现了另一个 SO 问题,其问题与我的问题有点不同,但足够接近:Create route in Spring Cloud Gateway with OAuth2 Resource Owner Password grant type 并且他提供了我可以开始工作的代码,因为与该代码库一起使用的 Provider 实际上是 PasswordReactiveOAuth2AuthorizedClientProvider
最后,我只需要在 yaml 文件中输入 3 项:client-id(之前将 client_id 作为 AccessTokenRequest 上的属性)、authorization-grant-type 和 token-uri 除此之外,我从 rigon 提供的代码中复制了 WebClient 和 ReactiveOAuth2AuthorizedClientManager 设置,并将配置文件中的用户名和密码放入设置中(我离开了单独的 contextAttributesMapper,因为我只需要直接在地图中提供 2 个上下文参数)。
【讨论】:
如果有人试图访问 Salesforce,这个示例对我来说效果很好:reddit.com/r/javahelp/comments/jpzg3o/…【参考方案2】:是的,RestTemplate 和 OAuthRestTemplate 都已弃用。 WebClient 支持开箱即用的 OAuth。您不需要做任何特别的事情或自己添加任何标题。它实际上非常微不足道。
创建一个公开 WebClient bean 的配置类,确保将客户端存储库作为参数。在该方法中,您将 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;
注意:在过滤器函数中,将“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
Aaaanddd....你完成了!还内置了 OAuth 令牌刷新。
【讨论】:
嗯,首先:Intellij 不理解 getHostName(),所以我猜你在同一个文件中有一个额外的方法。其次,在旧代码中,client_id(是的,下划线,不是连字符,我刚刚看到)作为属性放在 AccessTokenRequest 中并放在 OAuthClientContext 中,我认为我需要使用与 client-id 相同的第三个,我仍然看不到服务帐户的用户名和密码应该放在哪里,我们没有使用机密。顺便说一句,我们使用的是 spring 5.2.2,不知道这是否有影响 @JeroenV getHostName() 方法只是我获取主机名的管道。您可以从任何您想要的地方拉取服务器 url。你把你的用户名和密码放在client-id和client-secret中。密码授予与客户端凭据授予相同。如果您了解 oAuth 的机制,它们基本上是相同的。是的,我正在使用最新的 Spring / Spring Boot。这是 Spring Security 5 的最新设置。 @JeroenV 扩展“它们是相同的”,只是 Spring Security 将它们放在 application.properties 中的相同位置。实际上,客户端凭据与密码流授权具有相同的机制,只是 HTTP 请求中的密钥名称不同。以上是关于Spring Security 5.2 / WebClient 使用用户名和密码连接到另一个服务的方式是啥?的主要内容,如果未能解决你的问题,请参考以下文章
Spring Boot /h2-console 使用 Spring Security 1.5.2 抛出 403
Spring Security(三十七):Part IV. Web Application Security
Maven Repository 上 4.1.1 中的 spring-security-web 在哪里?
web应用安全框架选型:Spring Security与Apache Shiro