Authorized Client Features
本部分介绍了 Spring Security 为 OAuth2 客户端提供的其他功能。
Resolving an Authorized Client
@RegisteredOAuth2AuthorizedClient
注解提供了将方法参数解析为类型为 OAuth2AuthorizedClient
的参数值的能力。与通过使用 OAuth2AuthorizedClientManager
或 OAuth2AuthorizedClientService
访问 OAuth2AuthorizedClient
相比,这是十分方便的替代方法。以下示例显示了如何使用 @RegisteredOAuth2AuthorizedClient
:
-
Java
-
Kotlin
@Controller
public class OAuth2ClientController {
@GetMapping("/")
public String index(@RegisteredOAuth2AuthorizedClient("okta") OAuth2AuthorizedClient authorizedClient) {
OAuth2AccessToken accessToken = authorizedClient.getAccessToken();
...
return "index";
}
}
@Controller
class OAuth2ClientController {
@GetMapping("/")
fun index(@RegisteredOAuth2AuthorizedClient("okta") authorizedClient: OAuth2AuthorizedClient): String {
val accessToken = authorizedClient.accessToken
...
return "index"
}
}
@RegisteredOAuth2AuthorizedClient
注解由 OAuth2AuthorizedClientArgumentResolver
处理,它直接使用 OAuth2AuthorizedClientManager
,因此继承了它的功能。
WebClient Integration for Servlet Environments
OAuth 2.0 客户端支持通过使用 xref:servlet/oauth2/client/core#oauth2Client-authorized-manager-provider.adoc.adoc[OAuth2AuthorizedClientManager
与 WebClient
集成。
ServletOAuth2AuthorizedClientExchangeFilterFunction
提供使用 OAuth2AuthorizedClient
并包括关联的 OAuth2AccessToken
作为承载令牌来请求受保护资源的机制。它直接使用 OAuth2AuthorizedClientManager
,因此继承了以下功能:
-
如果客户端尚未获得授权,则请求
OAuth2AccessToken
。-
authorization_code
:触发授权请求重定向以启动流程。 -
client_credentials
:直接从令牌终结点获取访问令牌。 -
password
:直接从令牌端点获取访问令牌。
-
-
如果
OAuth2AccessToken
已过期,如果OAuth2AuthorizedClientProvider
可用于执行授权,它将进行刷新(或更新)。
下面的代码展示了如何将 OAuth2AuthorizedClientManager
与 OAuth 2.0 客户端支持进行配置的一个示例:
-
Java
-
Kotlin
@Bean
WebClient webClient(OAuth2AuthorizedClientManager authorizedClientManager) {
ServletOAuth2AuthorizedClientExchangeFilterFunction oauth2Client =
new ServletOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager);
return WebClient.builder()
.apply(oauth2Client.oauth2Configuration())
.build();
}
@Bean
fun webClient(authorizedClientManager: OAuth2AuthorizedClientManager?): WebClient {
val oauth2Client = ServletOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager)
return WebClient.builder()
.apply(oauth2Client.oauth2Configuration())
.build()
}
Providing the Authorized Client
xref:servlet/oauth2/client/core#oauth2Client-authorized-manager-provider.adoc.adoc[OAuth2AuthorizedClientManager
通过从 WebClient
(请求属性)解析 ServletOAuth2AuthorizedClientExchangeFilterFunction
来确定要用于(一个请求的)客户端。
下面的代码展示了如何将 OAuth2AuthorizedClient
设置为请求属性:
-
Java
-
Kotlin
@GetMapping("/")
public String index(@RegisteredOAuth2AuthorizedClient("okta") OAuth2AuthorizedClient authorizedClient) {
String resourceUri = ...
String body = webClient
.get()
.uri(resourceUri)
.attributes(oauth2AuthorizedClient(authorizedClient)) 1
.retrieve()
.bodyToMono(String.class)
.block();
...
return "index";
}
@GetMapping("/")
fun index(@RegisteredOAuth2AuthorizedClient("okta") authorizedClient: OAuth2AuthorizedClient): String {
val resourceUri: String = ...
val body: String = webClient
.get()
.uri(resourceUri)
.attributes(oauth2AuthorizedClient(authorizedClient)) 1
.retrieve()
.bodyToMono()
.block()
...
return "index"
}
1 | oauth2AuthorizedClient() 是 ServletOAuth2AuthorizedClientExchangeFilterFunction 中的 static 方法。 |
下面的代码展示了如何将 ClientRequest.attributes()
设置为请求属性:
-
Java
-
Kotlin
@GetMapping("/")
public String index() {
String resourceUri = ...
String body = webClient
.get()
.uri(resourceUri)
.attributes(clientRegistrationId("okta")) 1
.retrieve()
.bodyToMono(String.class)
.block();
...
return "index";
}
@GetMapping("/")
fun index(): String {
val resourceUri: String = ...
val body: String = webClient
.get()
.uri(resourceUri)
.attributes(clientRegistrationId("okta")) 1
.retrieve()
.bodyToMono()
.block()
...
return "index"
}
1 | clientRegistrationId() 是 ServletOAuth2AuthorizedClientExchangeFilterFunction 中的 static 方法。 |
下面的代码展示了如何将 OAuth2AuthorizedClient
设置为请求属性:
-
Java
-
Kotlin
@GetMapping("/")
public String index() {
String resourceUri = ...
Authentication anonymousAuthentication = new AnonymousAuthenticationToken(
"anonymous", "anonymousUser", AuthorityUtils.createAuthorityList("ROLE_ANONYMOUS"));
String body = webClient
.get()
.uri(resourceUri)
.attributes(authentication(anonymousAuthentication)) 1
.retrieve()
.bodyToMono(String.class)
.block();
...
return "index";
}
@GetMapping("/")
fun index(): String {
val resourceUri: String = ...
val anonymousAuthentication: Authentication = AnonymousAuthenticationToken(
"anonymous", "anonymousUser", AuthorityUtils.createAuthorityList("ROLE_ANONYMOUS"))
val body: String = webClient
.get()
.uri(resourceUri)
.attributes(authentication(anonymousAuthentication)) 1
.retrieve()
.bodyToMono()
.block()
...
return "index"
}
1 | authentication() 是 ServletOAuth2AuthorizedClientExchangeFilterFunction 中的 static 方法。 |
It is recommended to be cautious with this feature since all HTTP requests will receive an access token bound to the provided principal.
Defaulting the Authorized Client
如果既没有 ClientRegistration.getRegistrationId()
也未在 Authentication
提供作为请求属性,则 OAuth2AuthorizedClient
可以根据其配置确定要使用的 ClientRegistration.getRegistrationId()
客户端。
如果 ServletOAuth2AuthorizedClientExchangeFilterFunction
已经配置,并且用户已经使用 default 进行了身份验证,则与当前 setDefaultOAuth2AuthorizedClient(true)
相关联的 HttpSecurity.oauth2Login()
被使用。
下面的代码展示了具体配置:
-
Java
-
Kotlin
@Bean
WebClient webClient(OAuth2AuthorizedClientManager authorizedClientManager) {
ServletOAuth2AuthorizedClientExchangeFilterFunction oauth2Client =
new ServletOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager);
oauth2Client.setDefaultOAuth2AuthorizedClient(true);
return WebClient.builder()
.apply(oauth2Client.oauth2Configuration())
.build();
}
@Bean
fun webClient(authorizedClientManager: OAuth2AuthorizedClientManager?): WebClient {
val oauth2Client = ServletOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager)
oauth2Client.setDefaultOAuth2AuthorizedClient(true)
return WebClient.builder()
.apply(oauth2Client.oauth2Configuration())
.build()
}
谨慎使用此功能,因为所有 HTTP 请求都会收到访问令牌。
或者,如果 OAuth2AccessToken
使用有效的 OAuth2AuthenticationToken
进行配置,则与 setDefaultClientRegistrationId("okta")
相关联的 ClientRegistration
被使用。
下面的代码展示了具体配置:
-
Java
-
Kotlin
@Bean
WebClient webClient(OAuth2AuthorizedClientManager authorizedClientManager) {
ServletOAuth2AuthorizedClientExchangeFilterFunction oauth2Client =
new ServletOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager);
oauth2Client.setDefaultClientRegistrationId("okta");
return WebClient.builder()
.apply(oauth2Client.oauth2Configuration())
.build();
}
@Bean
fun webClient(authorizedClientManager: OAuth2AuthorizedClientManager?): WebClient {
val oauth2Client = ServletOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager)
oauth2Client.setDefaultClientRegistrationId("okta")
return WebClient.builder()
.apply(oauth2Client.oauth2Configuration())
.build()
}
谨慎使用此功能,因为所有 HTTP 请求都会收到访问令牌。