简体   繁体   English

使用 Spring Security OAuth 时,Spring Boot Reactive WebClient “serverWebExchange must be null”

[英]Spring Boot Reactive WebClient "serverWebExchange must be null" when Spring Security OAuth is in use

I would like to use a WebClient from a Spring Boot WebFlux app that is set up with Spring Security OAuth 2 Client Credentials.我想使用使用 Spring Security OAuth 2 客户端凭据设置的 Spring Boot WebFlux 应用程序中的 WebClient。

But, I get: java.lang.IllegalArgumentException: serverWebExchange must be null但是,我得到: java.lang.IllegalArgumentException: serverWebExchange must be null

The code is here: https://github.com/mparaz/spring-apigee-client代码在这里: https : //github.com/mparaz/spring-apigee-client

When I disable Spring Security by removing it from the pom.xml , it works properly.当我通过从pom.xml删除它来禁用 Spring Security 时,它可以正常工作。

When I keep using Spring Security, but instead of returning the webClient() chain result to the controller, and just prints it out, it also works.当我继续使用 Spring Security 时,而不是将webClient()链结果返回给控制器,而是将其打印出来,它也可以工作。

It looks like the Reactive client and server don't work together when Spring Security is used.使用 Spring Security 时,Reactive 客户端和服务器似乎无法协同工作。 How could I get them running together?我怎样才能让它们一起运行?

It seems that if you use an UnAuthenticatedServerOAuth2AuthorizedClientRepository it will propagate the webExchange from the source request going into to your @RestController into the WebClient you are using to invoke the other service causing the java.lang.IllegalArgumentException: serverWebExchange must be null看来,如果您使用UnAuthenticatedServerOAuth2AuthorizedClientRepository它会将 webExchange 从源请求传播到您的@RestController到您用来调用其他服务的WebClient中,从而导致java.lang.IllegalArgumentException: serverWebExchange must be null

To fix this, use the autowired implementation of the ServerOAuth2AuthorizedClientRepository (this happens to be AuthenticatedPrincipalServerOAuth2AuthorizedClientRepository )要解决此问题,请使用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;
    }

For me the problem was following对我来说,问题在于

https://docs.spring.io/spring-security/site/docs/5.5.x/reference/html5/#oauth2Client-authorized-manager-provider 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.

Comment on the following link worked for me评论以下链接对我有用

https://www.gitmemory.com/issue/spring-projects/spring-security/8444/621567261

Another link另一个链接

https://github.com/spring-projects/spring-security/issues/8230

Comment评论

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.

Actual code实际代码

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

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

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