使用ClientRegistrationId作为请求属性的WebClient(使用OAuth 2.0)

r7xajy2e  于 2023-08-02  发布在  其他
关注(0)|答案(3)|浏览(121)

我正在寻找一个工作示例,当我向WebClient添加请求属性时,我可以在其中设置ClientRegistrationId。www.example.com提供的示例spring.io对我不起作用(docs.spring.io(5.2.12))。
当我尝试这个例子时(使用默认的ClientRegistrationId):

@Bean
WebClient webClient(ReactiveClientRegistrationRepository clientRegistrations,
        ServerOAuth2AuthorizedClientRepository authorizedClients) {
    ServerOAuth2AuthorizedClientExchangeFilterFunction oauth =
            new ServerOAuth2AuthorizedClientExchangeFilterFunction(clientRegistrations, authorizedClients);
    // (optional) explicitly opt into using the oauth2Login to provide an access token implicitly
    // oauth.setDefaultOAuth2AuthorizedClient(true);
    // (optional) set a default ClientRegistration.registrationId
    oauth.setDefaultClientRegistrationId("MyClRegId");
    return WebClient.builder()
            .filter(oauth)
            .build();
}

字符串
调用端点:

ResponseSpec responseSpec = this.webClient.get().uri("/NumberOrders").retrieve();


Application.Properties:

spring.security.oauth2.client.registration.MyClRegId.authorization-grant-type=client_credentials
spring.security.oauth2.client.registration.MyClRegId.client-id=myteam
spring.security.oauth2.client.registration.MyClRegId.client-secret=12349875
spring.security.oauth2.client.provider.MyClRegId.token-uri=https://something/token
spring.security.oauth2.client.registration.MyClRegId.scope=OIDC


我得到以下错误:

  • 原因:java.lang.IllegalArgumentException:serverWebExchange不能为null*

如果我尝试将ClientRegestrationId设置为相应的请求属性spring.io示例(docs.spring.io(5.2.12)),则会出现另一个错误(The Method clientRegestrationId(String)is undefined ...):

ResponseSpec responseSpec = this.webClient
        .get()
        .attributes(clientRegistrationId("client-id"))
        .uri("/NumberOrders")
        .retrieve();


这个错误并不奇怪,因为这个方法实际上并不存在,但是有人有这样一个方法的例子吗?属性需要***Consumer<Map<String,Object>> attributesConsumer***作为输入以设置ClientRegistrationId。当然,它应该工作,没有第一个错误(*serverWebExchange不能为空 *)。
我在这里找到了一个工作设置WebClient OAuth2(答案由clocken提供),但ClientRegistrationId是在Bean中设置的。我想在调用端点时设置它。因此,我可以在我的application.properties中使用不同的配置(使用不同的ClientRegistrationId)。
也许有一种方法可以在设置WebClient.Builder时设置ClientRegistrationId?
我找了很多,但我找不到任何答案。提前感谢您的帮助。
我使用这个依赖项:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.5.4</version>
    <relativePath />
</parent>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>

t1qtbnec

t1qtbnec1#

您可以使用

webClient.get()
  .uri("http://localhost:8084/retrieve-resource")
  .attributes(
    ServerOAuth2AuthorizedClientExchangeFilterFunction
      .clientRegistrationId("bael"))
  .retrieve()
  // ...

字符串
下面是完整的代码:https://www.baeldung.com/spring-webclient-oauth2

nnsrf1az

nnsrf1az2#

这是您所提到的示例中所需的配置:
AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager AuthorizedClientManager
serverWebExchange cannot be null是在webClient调用由用户操作以外的东西触发时抛出的,例如Kafka事件触发了webClient调用,因此没有Request Context。
授权客户端服务... bean被定义为负责由事件触发的webClient调用,调度任务线程。
服务对服务通信

83qze16e

83qze16e3#

这就是我如何实现我的一个springboot应用程序,它使用webflux,springboot版本2.6.5进行响应,并在ServerWebExchange的上下文之外操作,例如。在调度/后台线程中和/或在服务层中。
最低配置为:

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.security.oauth2.client.*;
import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository;
import org.springframework.security.oauth2.client.web.reactive.function.client.ServerOAuth2AuthorizedClientExchangeFilterFunction;
import org.springframework.web.reactive.function.client.WebClient;

@Configuration
@Slf4j
public class MyWebClient {

    @Bean
    @Qualifier("someWebClient") // -----> 1
    public WebClient someWebClient(ReactiveOAuth2AuthorizedClientManager authorizedClientManager) {
        ServerOAuth2AuthorizedClientExchangeFilterFunction oauth =
                new ServerOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager);
        return WebClient.builder().filter(oauth).build();
    }

    @Bean
    public ReactiveOAuth2AuthorizedClientManager authorizedClientManager(
            ReactiveClientRegistrationRepository clientRegistrationRepository,
            ReactiveOAuth2AuthorizedClientService authorizedClientService) { // -----> 2, 3
        ReactiveOAuth2AuthorizedClientProvider authorizedClientProvider =
                ReactiveOAuth2AuthorizedClientProviderBuilder.builder().clientCredentials().build(); // -----> 4
        AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager authorizedClientManager =
                new AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager(clientRegistrationRepository,
                                                                                 authorizedClientService);
        authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider); // -----> 5
        return authorizedClientManager;
    }
}

字符串

application.yaml

spring:
  security:
    oauth2:
      client:
        provider:
          my-token-provider:
            token-uri: https://uri-used-to-generate-token
        registration:
          my-token-clientid:
            authorization-grant-type: client_credentials
            client-authentication-method: post
            client-id: clientIdReplacewithYour
            client-secret: clientSecretReplaceWithYour
            provider: my-token-provider

使用webClient:

return webClient
            .method(method)
            .uri(uri)
            .body(Mono.justOrEmpty(requestBody), Object.class)
            .headers(headers)
            .attributes(ServerOAuth2AuthorizedClientExchangeFilterFunction.clientRegistrationId(clientId)) // -----> 6
            .exchangeToMono(responseHandler);


上面代码中的注解指出了一些细节:
1.我用限定符"someWebClient"创建了WebClient bean,因为我想在注入时在另一个类中使用该限定符

  1. ReactiveClientRegistrationRepository clientRegistrationRepository将自动创建并通过springboot传递,默认配置为
  2. ReactiveOAuth2AuthorizedClientService authorizedClientService将自动创建并通过springboot传递,默认配置为
    1.我使用了clientCredentials(),因为我正在使用machine-machine,在ServerWebExchange上下文之外操作的AKS,没有控制器的AKS等。这一行是可选的,因为它已经在AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager类(如private static final ReactiveOAuth2AuthorizedClientProvider DEFAULT_AUTHORIZED_CLIENT_PROVIDER = ReactiveOAuth2AuthorizedClientProviderBuilder.builder().clientCredentials().build();)中预定义了
  3. authorizedClientManager.setAuthorizedClientProvider-如果您构建了自己的ReactiveOAuth2AuthorizedClientProvider并希望在默认情况下使用它,请使用此选项。如果你想使用springboot的开箱即用配置,不要在代码中添加this和point 4。
    1.将clientId作为参数传递-如果application.yaml中有多个clientId,则可以将clientId作为参数发送。

相关问题