核心的接口和类
本站(springdoc.cn)中的内容来源于 spring.io ,原始版权归属于 spring.io。由 springdoc.cn 进行翻译,整理。可供个人学习、研究,未经许可,不得进行任何转载、商用或与之相关的行为。 商标声明:Spring 是 Pivotal Software, Inc. 在美国以及其他国家的商标。 |
ClientRegistration
ClientRegistration
是一个在OAuth 2.0或OpenID Connect 1.0提供商处注册的客户端的表示。
客户端注册持有的信息,如 client id、client secret、授权授予类型、重定向URI、scope、授权URI、令牌URI和其他细节。
ClientRegistration
和它的属性定义如下。
public final class ClientRegistration {
private String registrationId; (1)
private String clientId; (2)
private String clientSecret; (3)
private ClientAuthenticationMethod clientAuthenticationMethod; (4)
private AuthorizationGrantType authorizationGrantType; (5)
private String redirectUri; (6)
private Set<String> scopes; (7)
private ProviderDetails providerDetails;
private String clientName; (8)
public class ProviderDetails {
private String authorizationUri; (9)
private String tokenUri; (10)
private UserInfoEndpoint userInfoEndpoint;
private String jwkSetUri; (11)
private String issuerUri; (12)
private Map<String, Object> configurationMetadata; (13)
public class UserInfoEndpoint {
private String uri; (14)
private AuthenticationMethod authenticationMethod; (15)
private String userNameAttributeName; (16)
}
}
}
1 | registrationId : ClientRegistration 的唯一ID标识。 |
2 | clientId : client id。 |
3 | clientSecret : client secret。 |
4 | clientAuthenticationMethod : 用于验证客户端和提供者的方法。支持的值是 client_secret_basic, client_secret_post, private_key_jwt, client_secret_jwt 和 none (public clients)。 |
5 | authorizationGrantType : OAuth 2.0 授权框架定义了四种 Authorization Grant 类型。支持的值是 authorization_code 、client_credentials 、password ,以及扩展 grant 类型 urn:ietf:params:oauth:grant-type:jwt-bearer 。 |
6 | redirectUri : 客户端注册的重定向URI,授权服务器在终端用户认证和授权访问客户端后将其重定向到终端用户的user-agent。 |
7 | scopes : 客户端在授权请求流程中要求的范围,如openid、电子邮件或个人资料。 |
8 | clientName : 用于客户端的描述性名称。这个名字可以在某些情况下使用,比如在自动生成的登录页面中显示客户端的名字。 |
9 | authorizationUri : 授权服务器的授权端点URI。 |
10 | tokenUri : 授权服务器的令牌(Token)端点URI。 |
11 | jwkSetUri : 用于从授权服务器检索 JSON网络密钥(JWK)集的URI,其中包含用于验证ID令牌的 JSON网络签名(JWS)的加密密钥,也可选择用户信息响应。 |
12 | issuerUri : 返回OpenID Connect 1.0提供者或OAuth 2.0授权服务器的 issuer 标识符URI。 |
13 | configurationMetadata : OpenID提供商配置信息。只有在配置了 Spring Boot 2.x 属性 spring.security.oauth2.client.provider.[providerId].issuerUri 时,该信息才可用。 |
14 | (userInfoEndpoint)uri : 用于访问已验证的终端用户的 claim/attribute 的UserInfo端点URI。 |
15 | (userInfoEndpoint)authenticationMethod : 向UserInfo端点发送访问令牌时使用的认证方法。支持的值是 header、form 和 query。 |
16 | userNameAttributeName : UserInfo 响应中返回的引用终端用户的名称或标识符(Identifier)的属性的名称。 |
ClientRegistrations
提供了方便的方法来配置一个 ClientRegistration
,在下面的例子中可以看到。
-
Java
-
Kotlin
ClientRegistration clientRegistration =
ClientRegistrations.fromIssuerLocation("https://idp.example.com/issuer").build();
val clientRegistration = ClientRegistrations.fromIssuerLocation("https://idp.example.com/issuer").build()
上面的代码将依次查询 idp.example.com/issuer/.well-known/openid-configuration
,然后是 idp.example.com/.well-known/openid-configuration/issuer
,最后是 idp.example.com/.well-known/oauth-authorization-server/issuer
,在第一个返回200响应的地方停止。
作为替代方案,你可以使用 ClientRegistrations.fromOidcIssuerLocation()
来只查询OpenID Connect Provider的配置端点。
ReactiveClientRegistrationRepository
ReactiveClientRegistrationRepository
作为OAuth 2.0 / OpenID Connect 1.0 ClientRegistration
的存储库(repository)。
客户注册信息最终由相关的授权服务器存储和拥有。这个 repository 提供了检索主要客户注册信息子集的能力,这些信息存储在授权服务器上。 |
Spring Boot 2.x的自动配置将 spring.security.oauth2.client.registration.[registrationId]
下的每个属性绑定到 ClientRegistration
的实例上,然后将每个 ClientRegistration
实例组合到 ReactiveClientRegistrationRepository
中。
ReactiveClientRegistrationRepository 的默认实现是 InMemoryReactiveClientRegistrationRepository 。
|
自动配置还将 ReactiveClientRegistrationRepository
注册为 ApplicationContext
中的 @Bean
,这样,如果应用程序需要,它就可以被依赖注入。
自动配置还将ReactiveClientRegistrationRepository注册为ApplicationContext中的@Bean,这样,如果应用程序需要,它就可以被依赖注入。
下面列出了一个例子。
-
Java
-
Kotlin
@Controller
public class OAuth2ClientController {
@Autowired
private ReactiveClientRegistrationRepository clientRegistrationRepository;
@GetMapping("/")
public Mono<String> index() {
return this.clientRegistrationRepository.findByRegistrationId("okta")
...
.thenReturn("index");
}
}
@Controller
class OAuth2ClientController {
@Autowired
private lateinit var clientRegistrationRepository: ReactiveClientRegistrationRepository
@GetMapping("/")
fun index(): Mono<String> {
return this.clientRegistrationRepository.findByRegistrationId("okta")
...
.thenReturn("index")
}
}
OAuth2AuthorizedClient
OAuth2AuthorizedClient
是一个授权客户端的代表。当终端用户(资源所有者)已经授权给客户端访问其受保护的资源时,客户端就被认为是被授权的。
OAuth2AuthorizedClient
的作用是将 OAuth2AccessToken
(和可选的 OAuth2RefreshToken
)与 ClientRegistration
(客户端)和资源所有者联系起来,后者是授予授权的 Principal
终端用户。
ServerOAuth2AuthorizedClientRepository / ReactiveOAuth2AuthorizedClientService
ServerOAuth2AuthorizedClientRepository
负责在Web请求之间持久保存 OAuth2AuthorizedClient
。而 ReactiveOAuth2AuthorizedClientService
的主要作用是在应用层面管理 OAuth2AuthorizedClient
。
从开发者的角度来看,ServerOAuth2AuthorizedClientRepository
或 ReactiveOAuth2AuthorizedClientService
提供了查询与客户端相关的 OAuth2AccessToken
的能力,以便它可以用来发起受保护的资源请求。
下面列出了一个例子。
-
Java
-
Kotlin
@Controller
public class OAuth2ClientController {
@Autowired
private ReactiveOAuth2AuthorizedClientService authorizedClientService;
@GetMapping("/")
public Mono<String> index(Authentication authentication) {
return this.authorizedClientService.loadAuthorizedClient("okta", authentication.getName())
.map(OAuth2AuthorizedClient::getAccessToken)
...
.thenReturn("index");
}
}
@Controller
class OAuth2ClientController {
@Autowired
private lateinit var authorizedClientService: ReactiveOAuth2AuthorizedClientService
@GetMapping("/")
fun index(authentication: Authentication): Mono<String> {
return this.authorizedClientService.loadAuthorizedClient<OAuth2AuthorizedClient>("okta", authentication.name)
.map { it.accessToken }
...
.thenReturn("index")
}
}
Spring Boot 2.x 的自动配置在 ApplicationContext 中注册了 ServerOAuth2AuthorizedClientRepository 和/或 ReactiveOAuth2AuthorizedClientService @Bean 。然而,应用程序可以选择覆盖并注册一个自定义的 ServerOAuth2AuthorizedClientRepository 或 ReactiveOAuth2AuthorizedClientService @Bean 。
|
ReactiveOAuth2AuthorizedClientService
的默认实现是 InMemoryReactiveOAuth2AuthorizedClientService
,它在内存中存储 OAuth2AuthorizedClient
。
另外,R2DBC实现 R2dbcReactiveOAuth2AuthorizedClientService
可以被配置为在数据库中持久化 OAuth2AuthorizedClient
。
R2dbcReactiveOAuth2AuthorizedClientService 依赖于 OAuth2.0客户端 Schema 中 描述的表定义。
|
ReactiveOAuth2AuthorizedClientManager / ReactiveOAuth2AuthorizedClientProvider
ReactiveOAuth2AuthorizedClientManager
负责 OAuth2AuthorizedClient
的整体管理。
主要职责包括:
-
使用
ReactiveOAuth2AuthorizedClientProvider
授权(或重新授权)一个OAuth 2.0客户端。 -
委托一个
OAuth2AuthorizedClient
的 persistence,通常使用ReactiveOAuth2AuthorizedClientService
或ServerOAuth2AuthorizedClientRepository
。 -
当一个OAuth 2.0客户端被成功授权(或重新授权)时,委托给一个
ReactiveOAuth2AuthorizationSuccessHandler
。 -
当 OAuth 2.0 客户端未能授权(或重新授权)时,委托给一个
ReactiveOAuth2AuthorizationFailureHandler
。
ReactiveOAuth2AuthorizedClientProvider
实现了一个授权(或重新授权)OAuth 2.0客户端的策略。实现通常会实现一个授权授予类型,例如 authorization_code
, client_credentials
等。
ReactiveOAuth2AuthorizedClientManager
的默认实现是 DefaultReactiveOAuth2AuthorizedClientManager
,它与 ReactiveOAuth2AuthorizedClientProvider
相关联,可以使用基于委托的复合支持多种授权授予类型。ReactiveOAuth2AuthorizedClientProviderBuilder
可以用来配置和构建基于委托的复合。
下面的代码显示了一个如何配置和构建 ReactiveOAuth2AuthorizedClientProvider
复合体的例子,它提供了对 authorization_code
、refresh_token
、client_credentials
和 password
授权 grant 类型的支持。
-
Java
-
Kotlin
@Bean
public ReactiveOAuth2AuthorizedClientManager authorizedClientManager(
ReactiveClientRegistrationRepository clientRegistrationRepository,
ServerOAuth2AuthorizedClientRepository authorizedClientRepository) {
ReactiveOAuth2AuthorizedClientProvider authorizedClientProvider =
ReactiveOAuth2AuthorizedClientProviderBuilder.builder()
.authorizationCode()
.refreshToken()
.clientCredentials()
.password()
.build();
DefaultReactiveOAuth2AuthorizedClientManager authorizedClientManager =
new DefaultReactiveOAuth2AuthorizedClientManager(
clientRegistrationRepository, authorizedClientRepository);
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
return authorizedClientManager;
}
@Bean
fun authorizedClientManager(
clientRegistrationRepository: ReactiveClientRegistrationRepository,
authorizedClientRepository: ServerOAuth2AuthorizedClientRepository): ReactiveOAuth2AuthorizedClientManager {
val authorizedClientProvider: ReactiveOAuth2AuthorizedClientProvider = ReactiveOAuth2AuthorizedClientProviderBuilder.builder()
.authorizationCode()
.refreshToken()
.clientCredentials()
.password()
.build()
val authorizedClientManager = DefaultReactiveOAuth2AuthorizedClientManager(
clientRegistrationRepository, authorizedClientRepository)
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider)
return authorizedClientManager
}
当授权尝试成功时,DefaultReactiveOAuth2AuthorizedClientManager
将委托给 ReactiveOAuth2AuthorizationSuccessHandler
,后者(默认)将通过 ServerOAuth2AuthorizedClientRepository
保存 OAuth2AuthorizedClient
。在重新授权失败的情况下,例如刷新令牌不再有效,先前保存的 OAuth2AuthorizedClient
将通过 RemoveAuthorizedClientReactiveOAuth2AuthorizationFailureHandler
从 ServerOAuth2AuthorizedClientRepository
删除。默认行为可以通过 setAuthorizationSuccessHandler(ReactiveOAuth2AuthorizationSuccessHandler)
和 setAuthorizationFailureHandler(ReactiveOAuth2AuthorizationFailureHandler)
定制。
DefaultReactiveOAuth2AuthorizedClientManager
还与一个 Function<OAuth2AuthorizeRequest, Mono<Map<String, Object>>
类型的 contextAttributesMapper
相关联,它负责将 OAuth2AuthorizeRequest
中的属性映射到与 OAuth2AuthorizationContext
相关联的属性 Map
。当你需要为 ReactiveOAuth2AuthorizedClientProvider
提供所需的(支持的)属性时,这可能很有用,例如,PasswordReactiveOAuth2AuthorizedClientProvider
要求资源所有者的用户名和密码在 OAuth2AuthorizationContext.getAttributes()
中可用。
下面的代码显示了 contextAttributesMapper
的一个例子。
-
Java
-
Kotlin
@Bean
public ReactiveOAuth2AuthorizedClientManager authorizedClientManager(
ReactiveClientRegistrationRepository clientRegistrationRepository,
ServerOAuth2AuthorizedClientRepository authorizedClientRepository) {
ReactiveOAuth2AuthorizedClientProvider authorizedClientProvider =
ReactiveOAuth2AuthorizedClientProviderBuilder.builder()
.password()
.refreshToken()
.build();
DefaultReactiveOAuth2AuthorizedClientManager authorizedClientManager =
new DefaultReactiveOAuth2AuthorizedClientManager(
clientRegistrationRepository, authorizedClientRepository);
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
// Assuming the `username` and `password` are supplied as `ServerHttpRequest` parameters,
// map the `ServerHttpRequest` parameters to `OAuth2AuthorizationContext.getAttributes()`
authorizedClientManager.setContextAttributesMapper(contextAttributesMapper());
return authorizedClientManager;
}
private Function<OAuth2AuthorizeRequest, Mono<Map<String, Object>>> contextAttributesMapper() {
return authorizeRequest -> {
Map<String, Object> contextAttributes = Collections.emptyMap();
ServerWebExchange exchange = authorizeRequest.getAttribute(ServerWebExchange.class.getName());
ServerHttpRequest request = exchange.getRequest();
String username = request.getQueryParams().getFirst(OAuth2ParameterNames.USERNAME);
String password = request.getQueryParams().getFirst(OAuth2ParameterNames.PASSWORD);
if (StringUtils.hasText(username) && StringUtils.hasText(password)) {
contextAttributes = new HashMap<>();
// `PasswordReactiveOAuth2AuthorizedClientProvider` requires both attributes
contextAttributes.put(OAuth2AuthorizationContext.USERNAME_ATTRIBUTE_NAME, username);
contextAttributes.put(OAuth2AuthorizationContext.PASSWORD_ATTRIBUTE_NAME, password);
}
return Mono.just(contextAttributes);
};
}
@Bean
fun authorizedClientManager(
clientRegistrationRepository: ReactiveClientRegistrationRepository,
authorizedClientRepository: ServerOAuth2AuthorizedClientRepository): ReactiveOAuth2AuthorizedClientManager {
val authorizedClientProvider: ReactiveOAuth2AuthorizedClientProvider = ReactiveOAuth2AuthorizedClientProviderBuilder.builder()
.password()
.refreshToken()
.build()
val authorizedClientManager = DefaultReactiveOAuth2AuthorizedClientManager(
clientRegistrationRepository, authorizedClientRepository)
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider)
// Assuming the `username` and `password` are supplied as `ServerHttpRequest` parameters,
// map the `ServerHttpRequest` parameters to `OAuth2AuthorizationContext.getAttributes()`
authorizedClientManager.setContextAttributesMapper(contextAttributesMapper())
return authorizedClientManager
}
private fun contextAttributesMapper(): Function<OAuth2AuthorizeRequest, Mono<MutableMap<String, Any>>> {
return Function { authorizeRequest ->
var contextAttributes: MutableMap<String, Any> = mutableMapOf()
val exchange: ServerWebExchange = authorizeRequest.getAttribute(ServerWebExchange::class.java.name)!!
val request: ServerHttpRequest = exchange.request
val username: String? = request.queryParams.getFirst(OAuth2ParameterNames.USERNAME)
val password: String? = request.queryParams.getFirst(OAuth2ParameterNames.PASSWORD)
if (StringUtils.hasText(username) && StringUtils.hasText(password)) {
contextAttributes = hashMapOf()
// `PasswordReactiveOAuth2AuthorizedClientProvider` requires both attributes
contextAttributes[OAuth2AuthorizationContext.USERNAME_ATTRIBUTE_NAME] = username!!
contextAttributes[OAuth2AuthorizationContext.PASSWORD_ATTRIBUTE_NAME] = password!!
}
Mono.just(contextAttributes)
}
}
DefaultReactiveOAuth2AuthorizedClientManager
被设计为在 ServerWebExchange
的 context中使用。当在 ServerWebExchange
context 之外操作时,请使用 AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager
代替。
对于何时使用 AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager
,服务应用(service application)是一个常见的用例。服务应用程序通常在后台运行,没有任何用户互动,并且通常在系统级账户下运行,而不是用户账户。一个配置了 client_credentials
grant 类型的OAuth 2.0客户端可以被认为是一种服务应用程序。
下面的代码显示了一个如何配置 AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager
的例子,它提供对 client_credentials
grant 类型的支持。
-
Java
-
Kotlin
@Bean
public ReactiveOAuth2AuthorizedClientManager authorizedClientManager(
ReactiveClientRegistrationRepository clientRegistrationRepository,
ReactiveOAuth2AuthorizedClientService authorizedClientService) {
ReactiveOAuth2AuthorizedClientProvider authorizedClientProvider =
ReactiveOAuth2AuthorizedClientProviderBuilder.builder()
.clientCredentials()
.build();
AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager authorizedClientManager =
new AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager(
clientRegistrationRepository, authorizedClientService);
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
return authorizedClientManager;
}
@Bean
fun authorizedClientManager(
clientRegistrationRepository: ReactiveClientRegistrationRepository,
authorizedClientService: ReactiveOAuth2AuthorizedClientService): ReactiveOAuth2AuthorizedClientManager {
val authorizedClientProvider: ReactiveOAuth2AuthorizedClientProvider = ReactiveOAuth2AuthorizedClientProviderBuilder.builder()
.clientCredentials()
.build()
val authorizedClientManager = AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager(
clientRegistrationRepository, authorizedClientService)
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider)
return authorizedClientManager
}