我想使用通过Spring Security OAuth 2客户端凭据设置的Spring Boot WebFlux应用程序中的WebClient。
但是,我得到了:java.lang.IllegalArgumentException: serverWebExchange must be null
代码在这里:https://github.com/mparaz/spring-apigee-client
当我通过从pom.xml
中删除Spring Security来禁用它时,它可以正常工作。
当我继续使用Spring Security时,而不是将webClient()
链结果返回给控制器,只是将其打印出来,它也可以工作。
使用Spring Security时,似乎Reactive客户端和服务器无法一起工作。我如何才能让他们一起运行?
答案 0 :(得分:1)
似乎,如果您使用UnAuthenticatedServerOAuth2AuthorizedClientRepository
,它将把webExchange从源请求传播到@RestController
到WebClient
中,您正在使用该服务调用其他服务,从而导致java.lang.IllegalArgumentException: serverWebExchange must be null
要解决此问题,请使用ServerOAuth2AuthorizedClientRepository
的自动连接实现(恰好是AuthenticatedPrincipalServerOAuth2AuthorizedClientRepository
)
@Bean
@LoadBalanced
public WebClient.Builder loadBalancedWebClientBuilder(ReactiveClientRegistrationRepository clientRegistrations,
ObjectMapper objectMapper,
ServerOAuth2AuthorizedClientRepository clientRepository) {
ServerOAuth2AuthorizedClientExchangeFilterFunction oauth2ClientFilter = new ServerOAuth2AuthorizedClientExchangeFilterFunction(
clientRegistrations,
clientRepository);
oauth2ClientFilter.setDefaultClientRegistrationId("apigee");
WebClient.Builder builder = WebClient.builder();
builder.defaultHeader("Content-Type", MediaType.APPLICATION_JSON.toString());
builder.defaultHeader("Accept", MediaType.APPLICATION_JSON.toString());
builder.filter(oauth2ClientFilter);
return builder;
}
答案 1 :(得分:0)
对我来说问题在于
The DefaultOAuth2AuthorizedClientManager is designed to be used within the context of a HttpServletRequest. When operating outside of a HttpServletRequest context, use AuthorizedClientServiceOAuth2AuthorizedClientManager instead.
评论以下链接对我有用
https://www.gitmemory.com/issue/spring-projects/spring-security/8444/621567261
另一个链接
https://github.com/spring-projects/spring-security/issues/8230
评论
DefaultReactiveOAuth2AuthorizedClientManager is intended to be used within a request context.
Given that you're seeing serverWebExchange cannot be null, you must be operating outside of a request context, which in case you should use AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager instead.
NOTE: Change the ServerOAuth2AuthorizedClientRepository parameter to ReactiveOAuth2AuthorizedClientService.
实际代码
@Bean
fun serverOAuth2AuthorizedClientExchangeFilterFunction(clientRegistrations: List<ClientRegistration>)
: ServerOAuth2AuthorizedClientExchangeFilterFunction {
val clientRegistrationRepository = InMemoryReactiveClientRegistrationRepository(clientRegistrations)
val authorizedClientService = InMemoryReactiveOAuth2AuthorizedClientService(clientRegistrationRepository)
val oAuth2AuthorizedClientManager = AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager(
clientRegistrationRepository,
authorizedClientService
)
val filterFunction = ServerOAuth2AuthorizedClientExchangeFilterFunction(oAuth2AuthorizedClientManager)
filterFunction.setDefaultClientRegistrationId(clientId)
return filterFunction
}