Authorized Clients

  • @RegisteredOAuth2AuthorizedClient 注解为解析方法参数提供了一种便捷方式,使其成为 OAuth2 授权客户端类型。

  • WebClient 集成允许使用 OAuth2 授权客户端和 OAuth2 访问令牌来请求受保护的资源。

  • ServerOAuth2AuthorizedClientExchangeFilterFunction 确定用于请求的客户端,并允许设置默认客户端。建议谨慎使用此功能,因为所有 HTTP 请求都将接收到访问令牌。

Resolving an Authorized Client

@RegisteredOAuth2AuthorizedClient 注解提供了解析方法参数到类型为 OAuth2AuthorizedClient 的参数值的可能性。与使用 ReactiveOAuth2AuthorizedClientManagerReactiveOAuth2AuthorizedClientService 访问 OAuth2AuthorizedClient 相比,这是一个便捷的替代方法。

The @RegisteredOAuth2AuthorizedClient annotation provides the capability of resolving a method parameter to an argument value of type OAuth2AuthorizedClient. This is a convenient alternative compared to accessing the OAuth2AuthorizedClient using the ReactiveOAuth2AuthorizedClientManager or ReactiveOAuth2AuthorizedClientService.

  • Java

  • Kotlin

@Controller
public class OAuth2ClientController {

	@GetMapping("/")
	public Mono<String> index(@RegisteredOAuth2AuthorizedClient("okta") OAuth2AuthorizedClient authorizedClient) {
		return Mono.just(authorizedClient.getAccessToken())
				...
				.thenReturn("index");
	}
}
@Controller
class OAuth2ClientController {
    @GetMapping("/")
    fun index(@RegisteredOAuth2AuthorizedClient("okta") authorizedClient: OAuth2AuthorizedClient): Mono<String> {
        return Mono.just(authorizedClient.accessToken)
                ...
                .thenReturn("index")
    }
}

@RegisteredOAuth2AuthorizedClient 注解由 OAuth2AuthorizedClientArgumentResolver 处理,它直接使用 ReactiveOAuth2AuthorizedClientManager 并因此继承了它的功能。

The @RegisteredOAuth2AuthorizedClient annotation is handled by OAuth2AuthorizedClientArgumentResolver, which directly uses a oauth2Client-authorized-manager-provider and therefore inherits it’s capabilities.

WebClient integration for Reactive Environments

OAuth 2.0 客户端支持通过使用 ExchangeFilterFunction 集成到 WebClient

The OAuth 2.0 Client support integrates with WebClient using an ExchangeFilterFunction.

ServerOAuth2AuthorizedClientExchangeFilterFunction 提供了一个简单的机制,通过使用 OAuth2AuthorizedClient 并包含关联 OAuth2AccessToken 作为 Bearer 令牌来请求受保护的资源。它直接使用 ReactiveOAuth2AuthorizedClientManager,因此继承了以下功能:

The ServerOAuth2AuthorizedClientExchangeFilterFunction provides a simple mechanism for requesting protected resources by using an OAuth2AuthorizedClient and including the associated OAuth2AccessToken as a Bearer Token. It directly uses an oauth2Client-authorized-manager-provider and therefore inherits the following capabilities:

  • An OAuth2AccessToken will be requested if the client has not yet been authorized.

    • authorization_code - triggers the Authorization Request redirect to initiate the flow

    • client_credentials - the access token is obtained directly from the Token Endpoint

    • password - the access token is obtained directly from the Token Endpoint

  • If the OAuth2AccessToken is expired, it will be refreshed (or renewed) if a ReactiveOAuth2AuthorizedClientProvider is available to perform the authorization

下面的代码展示了如何将 OAuth2AuthorizedClientManager 与 OAuth 2.0 客户端支持进行配置的一个示例:

The following code shows an example of how to configure WebClient with OAuth 2.0 Client support:

  • Java

  • Kotlin

@Bean
WebClient webClient(ReactiveOAuth2AuthorizedClientManager authorizedClientManager) {
	ServerOAuth2AuthorizedClientExchangeFilterFunction oauth2Client =
			new ServerOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager);
	return WebClient.builder()
			.filter(oauth2Client)
			.build();
}
@Bean
fun webClient(authorizedClientManager: ReactiveOAuth2AuthorizedClientManager): WebClient {
    val oauth2Client = ServerOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager)
    return WebClient.builder()
            .filter(oauth2Client)
            .build()
}

Providing the Authorized Client

ServerOAuth2AuthorizedClientExchangeFilterFunction 通过从 ClientRequest.attributes()(请求属性)中解析 OAuth2AuthorizedClient 确定要用于(一个请求)的客户端。

The ServerOAuth2AuthorizedClientExchangeFilterFunction determines the client to use (for a request) by resolving the OAuth2AuthorizedClient from the ClientRequest.attributes() (request attributes).

下面的代码展示了如何将 OAuth2AuthorizedClient 设置为请求属性:

The following code shows how to set an OAuth2AuthorizedClient as a request attribute:

  • Java

  • Kotlin

@GetMapping("/")
public Mono<String> index(@RegisteredOAuth2AuthorizedClient("okta") OAuth2AuthorizedClient authorizedClient) {
	String resourceUri = ...

	return webClient
			.get()
			.uri(resourceUri)
			.attributes(oauth2AuthorizedClient(authorizedClient))   1
			.retrieve()
			.bodyToMono(String.class)
			...
			.thenReturn("index");
}
@GetMapping("/")
fun index(@RegisteredOAuth2AuthorizedClient("okta") authorizedClient: OAuth2AuthorizedClient): Mono<String> {
    val resourceUri: String = ...

    return webClient
            .get()
            .uri(resourceUri)
            .attributes(oauth2AuthorizedClient(authorizedClient)) 1
            .retrieve()
            .bodyToMono<String>()
            ...
            .thenReturn("index")
}
1 oauth2AuthorizedClient() is a static method in ServerOAuth2AuthorizedClientExchangeFilterFunction.

下面的代码展示了如何将 ClientRequest.attributes() 设置为请求属性:

The following code shows how to set the ClientRegistration.getRegistrationId() as a request attribute:

  • Java

  • Kotlin

@GetMapping("/")
public Mono<String> index() {
	String resourceUri = ...

	return webClient
			.get()
			.uri(resourceUri)
			.attributes(clientRegistrationId("okta"))   1
			.retrieve()
			.bodyToMono(String.class)
			...
			.thenReturn("index");
}
@GetMapping("/")
fun index(): Mono<String> {
    val resourceUri: String = ...

    return webClient
            .get()
            .uri(resourceUri)
            .attributes(clientRegistrationId("okta"))  1
            .retrieve()
            .bodyToMono<String>()
            ...
            .thenReturn("index")
}
1 clientRegistrationId() is a static method in ServerOAuth2AuthorizedClientExchangeFilterFunction.

Defaulting the Authorized Client

如果 OAuth2AuthorizedClientClientRegistration.getRegistrationId() 未提供为请求属性,则 ServerOAuth2AuthorizedClientExchangeFilterFunction 可以根据它的配置确定要使用的 default 客户端。

If neither OAuth2AuthorizedClient or ClientRegistration.getRegistrationId() is provided as a request attribute, the ServerOAuth2AuthorizedClientExchangeFilterFunction can determine the default client to use depending on it’s configuration.

如果配置了 setDefaultOAuth2AuthorizedClient(true),并且用户已使用 ServerHttpSecurity.oauth2Login() 进行身份验证,则与当前 OAuth2AuthenticationToken 关联的 OAuth2AccessToken 被使用。

If setDefaultOAuth2AuthorizedClient(true) is configured and the user has authenticated using ServerHttpSecurity.oauth2Login(), the OAuth2AccessToken associated with the current OAuth2AuthenticationToken is used.

下面的代码展示了具体配置:

The following code shows the specific configuration:

  • Java

  • Kotlin

@Bean
WebClient webClient(ReactiveOAuth2AuthorizedClientManager authorizedClientManager) {
	ServerOAuth2AuthorizedClientExchangeFilterFunction oauth2Client =
			new ServerOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager);
	oauth2Client.setDefaultOAuth2AuthorizedClient(true);
	return WebClient.builder()
			.filter(oauth2Client)
			.build();
}
@Bean
fun webClient(authorizedClientManager: ReactiveOAuth2AuthorizedClientManager): WebClient {
    val oauth2Client = ServerOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager)
    oauth2Client.setDefaultOAuth2AuthorizedClient(true)
    return WebClient.builder()
            .filter(oauth2Client)
            .build()
}

建议慎用此功能,因为所有 HTTP 请求都将收到访问令牌。

It is recommended to be cautious with this feature since all HTTP requests will receive the access token.

或者,如果 OAuth2AccessToken 使用有效的 OAuth2AuthenticationToken 进行配置,则与 setDefaultClientRegistrationId("okta") 相关联的 ClientRegistration 被使用。

Alternatively, if setDefaultClientRegistrationId("okta") is configured with a valid ClientRegistration, the OAuth2AccessToken associated with the OAuth2AuthorizedClient is used.

下面的代码展示了具体配置:

The following code shows the specific configuration:

  • Java

  • Kotlin

@Bean
WebClient webClient(ReactiveOAuth2AuthorizedClientManager authorizedClientManager) {
	ServerOAuth2AuthorizedClientExchangeFilterFunction oauth2Client =
			new ServerOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager);
	oauth2Client.setDefaultClientRegistrationId("okta");
	return WebClient.builder()
			.filter(oauth2Client)
			.build();
}
@Bean
fun webClient(authorizedClientManager: ReactiveOAuth2AuthorizedClientManager): WebClient {
    val oauth2Client = ServerOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager)
    oauth2Client.setDefaultClientRegistrationId("okta")
    return WebClient.builder()
            .filter(oauth2Client)
            .build()
}

建议慎用此功能,因为所有 HTTP 请求都将收到访问令牌。

It is recommended to be cautious with this feature since all HTTP requests will receive the access token.