Spring Security 如何将非默认用户的Oauth标识关联到WebClient?

smdncfj3  于 2023-06-06  发布在  Spring
关注(0)|答案(1)|浏览(471)

我正在构建一个服务,它将允许用户将多个oauth身份与他们的帐户相关联,然后根据任何/所有身份检索信息。
我使用Spring提供的R2dbcReactiveOAuth2AuthorizedClientService将oauth身份存储在Postgres中。我目前的挑战是将保存的Oauth标识关联到WebClient,以便信息基于该Oauth标识。
基于ServerOAuth2AuthorizedClientExchangeFilterFunction.oauth2AuthorizedClient的JavaDoc,我可以传递OAuth2AuthorizedClient,它将对WebClient.retrieve()使用该标识。
修改ClientRequest.attributes()以包含用于提供承载令牌的OAuth2 AuthorizedClient。示例用法:

WebClient webClient = WebClient.builder()
     .filter(new ServerOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager))
     .build();
  Mono<String> response = webClient
     .get()
     .uri(uri)
     .attributes(oauth2AuthorizedClient(authorizedClient))
     // ...
     .retrieve()
     .bodyToMono(String.class);

基于调试,我当前的代码成功地从数据库加载了oauth标识,并将其作为属性添加到WebClient。当WebClient检索时,我得到错误IllegalArgumentException: serverWebExchange cannot be null。SO上的其他问题涉及到这个错误,表明当您混合使用servlet和响应式调用时会发生这个错误。然而,我只有WebFlux作为maven依赖项,所以我很确定这里不会发生这种情况。
关于如何解决/继续的任何建议?
我的产品服务

public class ProductService {
    private final ReactiveOAuth2AuthorizedClientService oAuth2AuthorizedClientService;
    private final ReactiveClientRegistrationRepository clientRegistrations;
    private static final String baseUri = "https://myapp.net/product";

    public ProductService(ReactiveOAuth2AuthorizedClientService oAuth2AuthorizedClientService,
            ReactiveClientRegistrationRepository clientRegistrations) {
        this.oAuth2AuthorizedClientService = oAuth2AuthorizedClientService;
        this.clientRegistrations = clientRegistrations;
    }

    public Mono<String> getNotifications(String productName, String userName) {
        String dataUri = "/{id}/notifications";
        Mono<OAuth2AuthorizedClient> userOauth = oAuth2AuthorizedClientService.loadAuthorizedClient("xxx", userName);
        Mono<Long> productId = this.lookupProductId(productName);

        return Mono.zip(productId, userOauth).checkpoint().flatMap(tuple2 ->
                this.getUserWebClient(userName).get()
                        .uri(uriBuilder -> uriBuilder
                                .path(dataUri)
                                .queryParam("datasource", "development")
                                .build(tuple2.getT1().toString()))
                        .attributes(ServerOAuth2AuthorizedClientExchangeFilterFunction.oauth2AuthorizedClient(tuple2.getT2()))
                        .retrieve()
                        .bodyToMono(String.class));
    }

    private WebClient getUserWebClient() {
        var authorizedClients = new AuthenticatedPrincipalServerOAuth2AuthorizedClientRepository(oAuth2AuthorizedClientService);
        var oauth = new ServerOAuth2AuthorizedClientExchangeFilterFunction(
                clientRegistrations, authorizedClients);
        return WebClient.builder()
                .baseUrl(baseUri)
                .filter(oauth)
                .build();
    }

    public Mono<Long> lookupProductId(String name) {
        // business logic to lookup product based on name
    }
}

Web安全配置使用Postgres存储库而不是默认的In-Memory bean

@Bean
public ReactiveOAuth2AuthorizedClientService dbOauth2AuthorizedClientService(DatabaseClient databaseClient,
        ReactiveClientRegistrationRepository clientRegistrationRepository) {
    return new R2dbcReactiveOAuth2AuthorizedClientService(databaseClient, clientRegistrationRepository);
}
t1rydlwq

t1rydlwq1#

在度过了一个愉快的暑假后,我在https://docs.spring.io/spring-security/reference/reactive/oauth2/client/core.html上找到并重新阅读了文档。这让我明白错误是由于没有ResponseContext,因为它在@Service组件中。暂时,我把它移到了一个@Controller中的一个@GetMapping
文档指出AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager可以用于@Service组件。我将尝试更新这个答案的代码,一旦我有它完成。

相关问题