spring-boot - OAuth2 机器与 Spring WebClient 的机器
问题描述
为了让 Spring WebClient 针对(可能)OAuth2 端点对我的服务进行身份验证,我已经苦苦挣扎了 2 天。流程很简单,我需要从某个端点获取令牌并将其设置为授权标头。我认为springboot可以透明地做到这一点。
这是配置我的 Web 客户端的一段代码:
private static final String SALES_FORCE = "sf";
@Bean
public WebClient salesforceClient(@Value("${salesforce.url}") String salesforceUrl,
ReactiveClientRegistrationRepository clientRegistrationRepository, ReactiveOAuth2AuthorizedClientService clientService) {
var clientManager = new AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager(clientRegistrationRepository, clientService);
var oauth2Client = new ServerOAuth2AuthorizedClientExchangeFilterFunction(clientManager);
oauth2Client.setDefaultClientRegistrationId(SALES_FORCE);
return WebClient.builder()
.baseUrl(salesforceUrl)
.filter(oauth2Client)
.build();
}
这是我的透明身份验证配置:
spring.security.oauth2.client.registration.sf.client-id=<secret_id>
spring.security.oauth2.client.registration.sf.client-secret=<secret_key>
spring.security.oauth2.client.registration.sf.authorization-grant-type=refresh_token
spring.security.oauth2.client.registration.sf.user-info-authentication-method=form
spring.security.oauth2.client.provider.sf.token-uri=https://auth.exacttargetapis.com/v1/requestToken
我花了一段时间才弄清楚要使用哪些 oauth2 类,但最终应用程序启动了。我用 localhost 上的 WireMock 替换了 token-uri ,结果发现 Spring 甚至没有尝试检索令牌。然后我用 WireMock 替换了我的目标服务器并返回 401,假设这会触发令牌检索或刷新,但 Spring 仍然没有获取令牌。
我已经开始考虑手动管理这个令牌检索/过期,因为 Spring 对我来说似乎太神奇了。
我究竟做错了什么?
PS。
根据来自 ServerOAuth2AuthorizedClientExchangeFilterFunction 的 javadoc 建议,我还尝试了第二个构造函数,它(大概)也自动管理令牌过期。
private static final String SALES_FORCE = "sf";
@Bean
public WebClient salesforceClient(@Value("${salesforce.url}") String salesforceUrl,
ReactiveClientRegistrationRepository clientRegistrationRepository
, ServerOAuth2AuthorizedClientRepository clientRepository) {
var oauth2Client = new ServerOAuth2AuthorizedClientExchangeFilterFunction(clientRegistrationRepository, clientRepository);
oauth2Client.setDefaultClientRegistrationId(SALES_FORCE);
return WebClient.builder()
.baseUrl(salesforceUrl)
.filter(oauth2Client)
.build();
}
但是在这里我的请求立即失败了
java.lang.IllegalArgumentException: serverWebExchange cannot be null
at org.springframework.security.oauth2.client.web.DefaultReactiveOAuth2AuthorizedClientManager.lambda$authorize$4(DefaultReactiveOAuth2AuthorizedClientManager.java:131)
Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException:
Error has been observed at the following site(s):
|_ checkpoint ⇢ Request to POST null [DefaultWebClient]
Stack trace:
at ....
总而言之,与手动管理安全令牌相比,我觉得 springboot WebClient 配置和使用过于复杂。
解决方案
切换ServerOAuth2AuthorizedClientRepository
到 aReactiveOAuth2AuthorizedClientService
将使代码运行:
@Bean
WebClient webClient(ReactiveClientRegistrationRepository clientRegistrations,
ReactiveOAuth2AuthorizedClientService authorizedClientService) {
ServerOAuth2AuthorizedClientExchangeFilterFunction oauth = new ServerOAuth2AuthorizedClientExchangeFilterFunction(new AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager(clientRegistrations, authorizedClientService));
oauth.setDefaultClientRegistrationId("myRegistrationId");
return WebClient.builder()
.filter(oauth)
.build();
}
建议使用ReactiveOAuth2AuthorizedClientManager
构造函数并传入AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager
.
推荐阅读
- django - 在 Django 2 中重定向和反向如何与 kwargs 一起工作?
- node.js - 如何通过 NodeJs 中的异步调用发出 POST 请求
- django - Django 检索组 ChoiceField 的键
- jboss - ActiveMQ 有正确的方言,但 SQL 语句不正确 AUTO_INCREMENT 而不是 IDENTITY 表创建
- javascript - 忽略 Google Cloud Console 测试中已完成功能的异常
- email - 从 kubernetes pod 发送电子邮件
- javascript - 未捕获的 SyntaxError:js 中带有 php 的意外标识符
- ios - 当 UICollectionViewCell 不调整大小时不应用前导和尾随约束
- assembly - 问题理解如何从堆栈访问内存
- javascript - 如何将 getElementById 与不同的 ID 名称结合起来