Spring boot Spring Boot反应式网络客户端“;serverWebExchange必须为空";当使用Spring Security OAuth时

Spring boot Spring Boot反应式网络客户端“;serverWebExchange必须为空";当使用Spring Security OAuth时,spring-boot,spring-security,spring-webflux,Spring Boot,Spring Security,Spring Webflux,我想使用Spring Boot WebFlux应用程序中的WebClient,该应用程序是使用Spring Security OAuth 2客户端凭据设置的 但是,我得到:java.lang.IllegalArgumentException:serverWebExchange必须为null 代码如下: 当我通过从pom.xml中删除它来禁用Spring安全性时,它可以正常工作 当我继续使用Spring安全性时,它不会将webClient()链结果返回给控制器并打印出来,而是同样有效 当使用Spr

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

但是,我得到:
java.lang.IllegalArgumentException:serverWebExchange必须为null

代码如下:

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

当我继续使用Spring安全性时,它不会将
webClient()
链结果返回给控制器并打印出来,而是同样有效


当使用Spring Security时,反应式客户端和服务器似乎无法协同工作。如何让它们一起运行?

如果您使用
未经验证的服务器OAuth2AuthorizedClientRepository
,它会将webExchange从源请求传播到您的
@RestController
WebClient
,您正在使用它来调用导致错误的其他服务
java.lang.IllegalArgumentException:serverWebExchange必须为null

要解决此问题,请使用
服务器OAuth2AuthorizedClient存储库的自动连线实现(这恰好是
AuthenticatedPrincipalServerOAuth2AuthorizedClient存储库


对我来说,问题就在后面

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

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
    }
@Bean
趣味服务器OAuth2AuthorizedClient ChangeFilterFunction(客户端注册:列表)
:ServerOAuth2AuthorizedClientExchangeFilterFunction{
val clientRegistrationRepository=InMemoryReactiveClientRegistrationRepository(clientRegistrations)
val authorizedClientService=InMemoryReactiveAuth2AuthorizedClientService(clientRegistrationRepository)
val OAuth2AuthorizedClient Manager=AuthorizedClient服务反应OAuth2AuthorizedClient Manager(
clientRegistrationRepository,
授权客户服务
)
val filterFunction=ServerOAuth2AuthorizedClientChangeFilterFunction(oAuth2AuthorizedClientManager)
filterFunction.setDefaultClientRegistrationId(clientId)
返回过滤器功能
}

您已经使用未经验证的回购/交换设置了webclient。本质上,它期望在反应式servlet上下文持有者上进行null或匿名身份验证。当它打电话时,谢谢@Darrenforsyth。你能建议我该怎么做吗?而不是:ServerOAuth2AuthorizedClientChangeFilterFunction oauth=new ServerOAuth2AuthorizedClientChangeFilterFunction(clientRegistrations,new Unauthenticated ServerOAuth2AuthorizedClientRepository());应该能够自动连线
服务器OAuth2AuthorizedClientRepository
,在中,只有两个具体的impl可用。UnAuthenticated是另一个没有与itI关联的主体的请求,我有完全相同的问题。当我通过单元测试调用受oauth2客户端凭据保护的资源时,一切正常。但是,当我通过未经验证的rest请求调用它时,它似乎传播了反应式servlet上下文持有者,而不是创建一个新的。您的“实际代码”无法编译。
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
    }