21. WebClient

Note

以下文档供在 Reactive 环境中使用。对于 Servlet 环境,请参考Servlet 的 WebClient环境。

Spring Framework 内置了对设置 Bearer 令牌的支持。

webClient.get()
    .headers(h -> h.setBearerAuth(token))
    ...

Spring Security 在此支持的基础上提供了其他好处:

  • Spring Security 将自动刷新过期的令牌(如果存在刷新令牌)

  • 如果请求访问令牌但不存在,则 Spring Security 将自动请求访问令牌。

  • 对于 authorization_code,这涉及执行重定向,然后重播原始请求

    • 对于 client_credentials,只需请求并保存令牌
  • 支持透明包含当前 OAuth 令牌或明确选择应使用的令牌的功能。

21.1 WebClient OAuth2 设置

第一步是确保正确设置WebClient。在完全反应的环境中设置WebClient的示例如下:

@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("client-registration-id");
    return WebClient.builder()
            .filter(oauth)
            .build();
}

21.2 隐式 OAuth2AuthorizedClient

如果我们将defaultOAuth2AuthorizedClient设置为有效的ClientRegistration id 的truein our setup and the user authenticated with oauth2Login (i.e. OIDC), then the current authentication is used to automatically provide the access token. Alternatively, if we set defaultClientRegistrationId,则该注册将用于提供访问令牌。这很方便,但是在并非所有端点都应获取访问令牌的环境中,这样做很危险(您可能为端点提供了错误的访问令牌)。

Mono<String> body = this.webClient
        .get()
        .uri(this.uri)
        .retrieve()
        .bodyToMono(String.class);

21.3 显式 OAuth2AuthorizedClient

OAuth2AuthorizedClient可以通过在请求属性上设置来明确提供。在下面的示例中,我们使用 Spring WebFlux 或 Spring MVC 参数解析器支持来解析OAuth2AuthorizedClient。但是,OAuth2AuthorizedClient的解析方式无关紧要。

@GetMapping("/explicit")
Mono<String> explicit(@RegisteredOAuth2AuthorizedClient("client-id") OAuth2AuthorizedClient authorizedClient) {
    return this.webClient
            .get()
            .uri(this.uri)
            .attributes(oauth2AuthorizedClient(authorizedClient))
            .retrieve()
            .bodyToMono(String.class);
}

21.4 clientRegistrationId

或者,可以在请求属性上指定clientRegistrationId,而WebClient将尝试查找OAuth2AuthorizedClient。如果找不到,将自动获取一个。

Mono<String> body = this.webClient
        .get()
        .uri(this.uri)
        .attributes(clientRegistrationId("client-id"))
        .retrieve()
        .bodyToMono(String.class);