使用 Spring Security OAuth 时 Spring Boot Reactive WebClient“serverWebExchange 必须为 null”

mpa*_*raz 6 spring-security spring-boot spring-webflux

我想使用 Spring Boot WebFlux 应用程序中的 WebClient,该应用程序是使用 Spring Security OAuth 2 客户端凭据设置的。

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

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

当我通过从 中删除 Spring Security 来禁用它时pom.xml,它可以正常工作。

当我继续使用 Spring Security,但不是将webClient()链结果返回到控制器,而是将其打印出来时,它也可以工作。

使用 Spring Security 时,Reactive 客户端和服务器似乎无法协同工作。我怎样才能让他们一起运行?

Lyn*_*nAs 6

对我来说问题如下

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.
Run Code Online (Sandbox Code Playgroud)

对以下链接的评论对我有用

https://www.gitmemory.com/issue/spring-projects/spring-security/8444/621567261
Run Code Online (Sandbox Code Playgroud)

另一个链接

https://github.com/spring-projects/spring-security/issues/8230
Run Code Online (Sandbox Code Playgroud)

评论

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.
Run Code Online (Sandbox Code Playgroud)

实际代码

    @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
    }
Run Code Online (Sandbox Code Playgroud)


bar*_*rtv 5

看来,如果您使用它,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;
    }
Run Code Online (Sandbox Code Playgroud)