使用Spring Security OAuth时,Spring Boot反应性WebClient“ serverWebExchange必须为空”

时间:2019-07-10 14:49:56

标签: spring-boot spring-security spring-webflux

我想使用通过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客户端和服务器无法一起工作。我如何才能让他们一起运行?

2 个答案:

答案 0 :(得分:1)

似乎,如果您使用UnAuthenticatedServerOAuth2AuthorizedClientRepository,它将把webExchange从源请求传播到@RestControllerWebClient中,您正在使用该服务调用其他服务,从而导致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)

对我来说问题在于

https://docs.spring.io/spring-security/site/docs/5.5.x/reference/html5/#oauth2Client-authorized-manager-provider

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
    }