Core Interfaces and Classes
本节介绍了 Spring Security 提供的 OAuth2 核心接口和类。
This section describes the OAuth2 core interfaces and classes that Spring Security offers.
ClientRegistration
OAuth2AccessToken
是向 OAuth 2.0 或 OpenID Connect 1.0 提供程序注册的客户端的表示形式。
ClientRegistration
is a representation of a client registered with an OAuth 2.0 or OpenID Connect 1.0 Provider.
OAuth2AuthorizedClient
对象包含诸如客户端 ID、客户端密钥、授权授予类型、重定向 URI、范围、授权 URI、令牌 URI 等信息和其他详细信息。
A ClientRegistration
object holds information, such as client id, client secret, authorization grant type, redirect URI, scope(s), authorization URI, token URI, and other details.
ClientRegistration
及其属性被定义如下:
ClientRegistration
and its properties are defined as follows:
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 : The ID that uniquely identifies the ClientRegistration . |
2 | clientId : The client identifier. |
3 | clientSecret : The client secret. |
4 | clientAuthenticationMethod : The method used to authenticate the Client with the Provider.
The supported values are client_secret_basic, client_secret_post, private_key_jwt, client_secret_jwt and none (public clients). |
5 | authorizationGrantType : The OAuth 2.0 Authorization Framework defines four Authorization Grant types.
The supported values are authorization_code , client_credentials , password , as well as, extension grant type urn:ietf:params:oauth:grant-type:jwt-bearer . |
6 | redirectUri : The client’s registered redirect URI that the Authorization Server redirects the end-user’s user-agent
to after the end-user has authenticated and authorized access to the client. |
7 | scopes : The scope(s) requested by the client during the Authorization Request flow, such as openid, email, or profile. |
8 | clientName : A descriptive name used for the client.
The name may be used in certain scenarios, such as when displaying the name of the client in the auto-generated login page. |
9 | authorizationUri : The Authorization Endpoint URI for the Authorization Server. |
10 | tokenUri : The Token Endpoint URI for the Authorization Server. |
11 | jwkSetUri : The URI used to retrieve the JSON Web Key (JWK) Set from the Authorization Server,
which contains the cryptographic key(s) used to verify the JSON Web Signature (JWS) of the ID Token and (optionally) the UserInfo Response. |
12 | issuerUri : Returns the issuer identifier URI for the OpenID Connect 1.0 provider or the OAuth 2.0 Authorization Server. |
13 | configurationMetadata : The OpenID Provider Configuration Information.
This information is available only if the Spring Boot 2.x property spring.security.oauth2.client.provider.[providerId].issuerUri is configured. |
14 | (userInfoEndpoint)uri : The UserInfo Endpoint URI used to access the claims and attributes of the authenticated end-user. |
15 | (userInfoEndpoint)authenticationMethod : The authentication method used when sending the access token to the UserInfo Endpoint.
The supported values are header, form, and query. |
16 | userNameAttributeName : The name of the attribute returned in the UserInfo Response that references the Name or Identifier of the end-user. |
你可以通过发现 OpenID Connect 提供程序的 ClientRegistration
或授权服务器的 ClientRegistration
初始配置 ClientRegistration
。
You can initially configure a ClientRegistration
by using discovery of an OpenID Connect Provider’s Configuration endpoint or an Authorization Server’s Metadata endpoint.
ClientRegistrations
提供方便的方法来按如下方式配置 ClientRegistration
:
ClientRegistrations
provides convenience methods for configuring a ClientRegistration
in this way, as follows:
-
Java
-
Kotlin
ClientRegistration clientRegistration =
ClientRegistrations.fromIssuerLocation("https://idp.example.com/issuer").build();
val clientRegistration = ClientRegistrations.fromIssuerLocation("https://idp.example.com/issuer").build()
上述代码按顺序查询 ClientRegistrations
、ClientRegistration
和 https://idp.example.com/issuer/.well-known/openid-configuration
,在第一个返回 200 响应时停止。
The preceding code queries, in series, https://idp.example.com/issuer/.well-known/openid-configuration
, https://idp.example.com/.well-known/openid-configuration/issuer
, and https://idp.example.com/.well-known/oauth-authorization-server/issuer
, stopping at the first to return a 200 response.
作为备用办法,您可以使用 ClientRegistrations.fromOidcIssuerLocation()
仅查询 OpenID Connect 提供程序的配置端点。
As an alternative, you can use ClientRegistrations.fromOidcIssuerLocation()
to query only the OpenID Connect Provider’s Configuration endpoint.
ClientRegistrationRepository
ClientRegistrationRepository
作为 OAuth 2.0/OpenID Connect 1.0 ClientRegistration
的储存库。
The ClientRegistrationRepository
serves as a repository for OAuth 2.0 / OpenID Connect 1.0 ClientRegistration
(s).
客户端注册信息最终由关联的授权服务器存储和拥有。该存储库提供了检索主要客户端注册信息子集的能力,该子集存储在授权服务器中。 Client registration information is ultimately stored and owned by the associated Authorization Server. This repository provides the ability to retrieve a subset of the primary client registration information, which is stored with the Authorization Server. |
Spring Boot 2.x 自动配置将 spring.security.oauth2.client.registration.[registrationId]
下的各个属性绑定到 ClientRegistration
的实例,然后将每个 ClientRegistration
实例组成到 ClientRegistrationRepository
中。
Spring Boot 2.x auto-configuration binds each of the properties under spring.security.oauth2.client.registration.[registrationId]
to an instance of ClientRegistration
and then composes each of the ClientRegistration
instance(s) within a ClientRegistrationRepository
.
The default implementation of |
自动配置还会在 ApplicationContext
中将 ClientRegistrationRepository
作为 @Bean
注册,以便它可用于依赖项注入(如果应用程序需要)。
The auto-configuration also registers the ClientRegistrationRepository
as a @Bean
in the ApplicationContext
so that it is available for dependency injection, if needed by the application.
下面的清单显示了一个示例:
The following listing shows an example:
-
Java
-
Kotlin
@Controller
public class OAuth2ClientController {
@Autowired
private ClientRegistrationRepository clientRegistrationRepository;
@GetMapping("/")
public String index() {
ClientRegistration oktaRegistration =
this.clientRegistrationRepository.findByRegistrationId("okta");
...
return "index";
}
}
@Controller
class OAuth2ClientController {
@Autowired
private lateinit var clientRegistrationRepository: ClientRegistrationRepository
@GetMapping("/")
fun index(): String {
val oktaRegistration =
this.clientRegistrationRepository.findByRegistrationId("okta")
//...
return "index";
}
}
OAuth2AuthorizedClient
OAuth2AuthorizedClient
是授权客户端的一个表示。当最终用户(资源所有者)已授予客户端访问其受保护资源的授权时,客户端被认为已获得授权。
OAuth2AuthorizedClient
is a representation of an Authorized Client.
A client is considered to be authorized when the end-user (the Resource Owner) has granted authorization to the client to access its protected resources.
OAuth2AuthorizedClient
的作用是将 OAuth2AccessToken
(和可选的 OAuth2RefreshToken
)关联到 ClientRegistration
(客户端)和资源所有者(即授予授权的 Principal
最终用户)。
OAuth2AuthorizedClient
serves the purpose of associating an OAuth2AccessToken
(and optional OAuth2RefreshToken
) to a ClientRegistration
(client) and resource owner, who is the Principal
end-user that granted the authorization.
OAuth2AuthorizedClientRepository and OAuth2AuthorizedClientService
OAuth2AuthorizedClientRepository
负责在 Web 请求之间持续存在 OAuth2AuthorizedClient
,而 OAuth2AuthorizedClientService
的主要作用是在应用程序级别管理 OAuth2AuthorizedClient
。
OAuth2AuthorizedClientRepository
is responsible for persisting OAuth2AuthorizedClient
(s) between web requests, whereas the primary role of OAuth2AuthorizedClientService
is to manage OAuth2AuthorizedClient
(s) at the application-level.
从开发人员的角度来看,OAuth2AuthorizedClientRepository
或 OAuth2AuthorizedClientService
提供了查找与客户端关联的 OAuth2AccessToken
的能力,以便它可用于发起受保护的资源请求。
From a developer perspective, the OAuth2AuthorizedClientRepository
or OAuth2AuthorizedClientService
provides the ability to look up an OAuth2AccessToken
associated with a client so that it can be used to initiate a protected resource request.
下面的清单显示了一个示例:
The following listing shows an example:
-
Java
-
Kotlin
@Controller
public class OAuth2ClientController {
@Autowired
private OAuth2AuthorizedClientService authorizedClientService;
@GetMapping("/")
public String index(Authentication authentication) {
OAuth2AuthorizedClient authorizedClient =
this.authorizedClientService.loadAuthorizedClient("okta", authentication.getName());
OAuth2AccessToken accessToken = authorizedClient.getAccessToken();
...
return "index";
}
}
@Controller
class OAuth2ClientController {
@Autowired
private lateinit var authorizedClientService: OAuth2AuthorizedClientService
@GetMapping("/")
fun index(authentication: Authentication): String {
val authorizedClient: OAuth2AuthorizedClient =
this.authorizedClientService.loadAuthorizedClient("okta", authentication.getName());
val accessToken = authorizedClient.accessToken
...
return "index";
}
}
Spring Boot 2.x 自动配置在 Spring Boot 2.x auto-configuration registers an |
OAuth2AuthorizedClientService
的默认实现是 InMemoryOAuth2AuthorizedClientService
,它在内存中存储 OAuth2AuthorizedClient
对象。
The default implementation of OAuth2AuthorizedClientService
is InMemoryOAuth2AuthorizedClientService
, which stores OAuth2AuthorizedClient
objects in-memory.
或者,您可以配置 JDBC 实现 JdbcOAuth2AuthorizedClientService
以将 OAuth2AuthorizedClient
实例持续存在于数据库中。
Alternatively, you can configure the JDBC implementation JdbcOAuth2AuthorizedClientService
to persist OAuth2AuthorizedClient
instances in a database.
|
OAuth2AuthorizedClientManager and OAuth2AuthorizedClientProvider
OAuth2AuthorizedClientManager
负责 OAuth2AuthorizedClient
的整体管理。
The OAuth2AuthorizedClientManager
is responsible for the overall management of OAuth2AuthorizedClient
(s).
主要职责包括:
The primary responsibilities include:
-
Authorizing (or re-authorizing) an OAuth 2.0 Client, by using an
OAuth2AuthorizedClientProvider
. -
Delegating the persistence of an
OAuth2AuthorizedClient
, typically by using anOAuth2AuthorizedClientService
orOAuth2AuthorizedClientRepository
. -
Delegating to an
OAuth2AuthorizationSuccessHandler
when an OAuth 2.0 Client has been successfully authorized (or re-authorized). -
Delegating to an
OAuth2AuthorizationFailureHandler
when an OAuth 2.0 Client fails to authorize (or re-authorize).
OAuth2AuthorizedClientProvider
实现了一个用于授权(或重新授权)OAuth 2.0 客户端的策略。实现通常实现授权赠款类型,例如 authorization_code
、client_credentials
和其他类型。
An OAuth2AuthorizedClientProvider
implements a strategy for authorizing (or re-authorizing) an OAuth 2.0 Client.
Implementations typically implement an authorization grant type, such as authorization_code
, client_credentials
, and others.
OAuth2AuthorizedClientManager
的默认实现是 DefaultOAuth2AuthorizedClientManager
,它与 OAuth2AuthorizedClientProvider
相关联,该后者可能使用基于委托的组合支持多个授权赠款类型。您可以使用 OAuth2AuthorizedClientProviderBuilder
配置和构建基于委托的组合。
The default implementation of OAuth2AuthorizedClientManager
is DefaultOAuth2AuthorizedClientManager
, which is associated with an OAuth2AuthorizedClientProvider
that may support multiple authorization grant types using a delegation-based composite.
You can use OAuth2AuthorizedClientProviderBuilder
to configure and build the delegation-based composite.
以下代码展示了如何配置和构建 OAuth2AuthorizedClientProvider
组合的一个示例,该组合为 authorization_code
、refresh_token
、client_credentials
和 password
授权赠款类型提供支持:
The following code shows an example of how to configure and build an OAuth2AuthorizedClientProvider
composite that provides support for the authorization_code
, refresh_token
, client_credentials
, and password
authorization grant types:
-
Java
-
Kotlin
@Bean
public OAuth2AuthorizedClientManager authorizedClientManager(
ClientRegistrationRepository clientRegistrationRepository,
OAuth2AuthorizedClientRepository authorizedClientRepository) {
OAuth2AuthorizedClientProvider authorizedClientProvider =
OAuth2AuthorizedClientProviderBuilder.builder()
.authorizationCode()
.refreshToken()
.clientCredentials()
.password()
.build();
DefaultOAuth2AuthorizedClientManager authorizedClientManager =
new DefaultOAuth2AuthorizedClientManager(
clientRegistrationRepository, authorizedClientRepository);
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
return authorizedClientManager;
}
@Bean
fun authorizedClientManager(
clientRegistrationRepository: ClientRegistrationRepository,
authorizedClientRepository: OAuth2AuthorizedClientRepository): OAuth2AuthorizedClientManager {
val authorizedClientProvider = OAuth2AuthorizedClientProviderBuilder.builder()
.authorizationCode()
.refreshToken()
.clientCredentials()
.password()
.build()
val authorizedClientManager = DefaultOAuth2AuthorizedClientManager(
clientRegistrationRepository, authorizedClientRepository)
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider)
return authorizedClientManager
}
当授权尝试成功时,DefaultOAuth2AuthorizedClientManager
将委托给 OAuth2AuthorizationSuccessHandler
,后者(默认情况下)通过 OAuth2AuthorizedClientRepository
保存 OAuth2AuthorizedClient
。如果重新授权失败(例如,刷新令牌不再有效),先前保存的 OAuth2AuthorizedClient
将通过 RemoveAuthorizedClientOAuth2AuthorizationFailureHandler
从 OAuth2AuthorizedClientRepository
中移除。您可以通过 setAuthorizationSuccessHandler(OAuth2AuthorizationSuccessHandler)
和 setAuthorizationFailureHandler(OAuth2AuthorizationFailureHandler)
自定义默认行为。
When an authorization attempt succeeds, the DefaultOAuth2AuthorizedClientManager
delegates to the OAuth2AuthorizationSuccessHandler
, which (by default) saves the OAuth2AuthorizedClient
through the OAuth2AuthorizedClientRepository
.
In the case of a re-authorization failure (for example, a refresh token is no longer valid), the previously saved OAuth2AuthorizedClient
is removed from the OAuth2AuthorizedClientRepository
through the RemoveAuthorizedClientOAuth2AuthorizationFailureHandler
.
You can customize the default behavior through setAuthorizationSuccessHandler(OAuth2AuthorizationSuccessHandler)
and setAuthorizationFailureHandler(OAuth2AuthorizationFailureHandler)
.
DefaultOAuth2AuthorizedClientManager
还与类型为 Function<OAuth2AuthorizeRequest, Map<String, Object>>
的 contextAttributesMapper
关联,后者负责将来自 OAuth2AuthorizeRequest
的属性映射到要与 OAuth2AuthorizationContext
关联的属性 Map
。这在需要为 OAuth2AuthorizedClientProvider
提供必需的(支持的)属性时很有用,例如。PasswordOAuth2AuthorizedClientProvider
要求 username
和 password
资源所有者的 OAuth2AuthorizationContext.getAttributes()
中可用。
The DefaultOAuth2AuthorizedClientManager
is also associated with a contextAttributesMapper
of type Function<OAuth2AuthorizeRequest, Map<String, Object>>
, which is responsible for mapping attribute(s) from the OAuth2AuthorizeRequest
to a Map
of attributes to be associated to the OAuth2AuthorizationContext
.
This can be useful when you need to supply an OAuth2AuthorizedClientProvider
with required (supported) attribute(s), eg. the PasswordOAuth2AuthorizedClientProvider
requires the resource owner’s username
and password
to be available in OAuth2AuthorizationContext.getAttributes()
.
以下代码显示了 contextAttributesMapper
的示例:
The following code shows an example of the contextAttributesMapper
:
-
Java
-
Kotlin
@Bean
public OAuth2AuthorizedClientManager authorizedClientManager(
ClientRegistrationRepository clientRegistrationRepository,
OAuth2AuthorizedClientRepository authorizedClientRepository) {
OAuth2AuthorizedClientProvider authorizedClientProvider =
OAuth2AuthorizedClientProviderBuilder.builder()
.password()
.refreshToken()
.build();
DefaultOAuth2AuthorizedClientManager authorizedClientManager =
new DefaultOAuth2AuthorizedClientManager(
clientRegistrationRepository, authorizedClientRepository);
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
// Assuming the `username` and `password` are supplied as `HttpServletRequest` parameters,
// map the `HttpServletRequest` parameters to `OAuth2AuthorizationContext.getAttributes()`
authorizedClientManager.setContextAttributesMapper(contextAttributesMapper());
return authorizedClientManager;
}
private Function<OAuth2AuthorizeRequest, Map<String, Object>> contextAttributesMapper() {
return authorizeRequest -> {
Map<String, Object> contextAttributes = Collections.emptyMap();
HttpServletRequest servletRequest = authorizeRequest.getAttribute(HttpServletRequest.class.getName());
String username = servletRequest.getParameter(OAuth2ParameterNames.USERNAME);
String password = servletRequest.getParameter(OAuth2ParameterNames.PASSWORD);
if (StringUtils.hasText(username) && StringUtils.hasText(password)) {
contextAttributes = new HashMap<>();
// `PasswordOAuth2AuthorizedClientProvider` requires both attributes
contextAttributes.put(OAuth2AuthorizationContext.USERNAME_ATTRIBUTE_NAME, username);
contextAttributes.put(OAuth2AuthorizationContext.PASSWORD_ATTRIBUTE_NAME, password);
}
return contextAttributes;
};
}
@Bean
fun authorizedClientManager(
clientRegistrationRepository: ClientRegistrationRepository,
authorizedClientRepository: OAuth2AuthorizedClientRepository): OAuth2AuthorizedClientManager {
val authorizedClientProvider = OAuth2AuthorizedClientProviderBuilder.builder()
.password()
.refreshToken()
.build()
val authorizedClientManager = DefaultOAuth2AuthorizedClientManager(
clientRegistrationRepository, authorizedClientRepository)
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider)
// Assuming the `username` and `password` are supplied as `HttpServletRequest` parameters,
// map the `HttpServletRequest` parameters to `OAuth2AuthorizationContext.getAttributes()`
authorizedClientManager.setContextAttributesMapper(contextAttributesMapper())
return authorizedClientManager
}
private fun contextAttributesMapper(): Function<OAuth2AuthorizeRequest, MutableMap<String, Any>> {
return Function { authorizeRequest ->
var contextAttributes: MutableMap<String, Any> = mutableMapOf()
val servletRequest: HttpServletRequest = authorizeRequest.getAttribute(HttpServletRequest::class.java.name)
val username: String = servletRequest.getParameter(OAuth2ParameterNames.USERNAME)
val password: String = servletRequest.getParameter(OAuth2ParameterNames.PASSWORD)
if (StringUtils.hasText(username) && StringUtils.hasText(password)) {
contextAttributes = hashMapOf()
// `PasswordOAuth2AuthorizedClientProvider` requires both attributes
contextAttributes[OAuth2AuthorizationContext.USERNAME_ATTRIBUTE_NAME] = username
contextAttributes[OAuth2AuthorizationContext.PASSWORD_ATTRIBUTE_NAME] = password
}
contextAttributes
}
}
DefaultOAuth2AuthorizedClientManager
被设计为在 HttpServletRequest
上下文中 within 使用的。当在 HttpServletRequest
上下文的 outside 中操作时,改用 AuthorizedClientServiceOAuth2AuthorizedClientManager
。
The DefaultOAuth2AuthorizedClientManager
is designed to be used within the context of a HttpServletRequest
.
When operating outside of a HttpServletRequest
context, use AuthorizedClientServiceOAuth2AuthorizedClientManager
instead.
服务应用程序是在何时使用 AuthorizedClientServiceOAuth2AuthorizedClientManager
的一个常见用例。服务应用程序通常在后台运行,没有任何用户交互,并且通常在系统级帐户下而不是用户帐户下运行。使用 client_credentials
授权类型配置的 OAuth 2.0 客户端可以被视为一种服务应用程序。
A service application is a common use case for when to use an AuthorizedClientServiceOAuth2AuthorizedClientManager
.
Service applications often run in the background, without any user interaction, and typically run under a system-level account instead of a user account.
An OAuth 2.0 Client configured with the client_credentials
grant type can be considered a type of service application.
以下代码显示了如何配置支持 client_credentials
授权类型的 AuthorizedClientServiceOAuth2AuthorizedClientManager
的示例:
The following code shows an example of how to configure an AuthorizedClientServiceOAuth2AuthorizedClientManager
that provides support for the client_credentials
grant type:
-
Java
-
Kotlin
@Bean
public OAuth2AuthorizedClientManager authorizedClientManager(
ClientRegistrationRepository clientRegistrationRepository,
OAuth2AuthorizedClientService authorizedClientService) {
OAuth2AuthorizedClientProvider authorizedClientProvider =
OAuth2AuthorizedClientProviderBuilder.builder()
.clientCredentials()
.build();
AuthorizedClientServiceOAuth2AuthorizedClientManager authorizedClientManager =
new AuthorizedClientServiceOAuth2AuthorizedClientManager(
clientRegistrationRepository, authorizedClientService);
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
return authorizedClientManager;
}
@Bean
fun authorizedClientManager(
clientRegistrationRepository: ClientRegistrationRepository,
authorizedClientService: OAuth2AuthorizedClientService): OAuth2AuthorizedClientManager {
val authorizedClientProvider = OAuth2AuthorizedClientProviderBuilder.builder()
.clientCredentials()
.build()
val authorizedClientManager = AuthorizedClientServiceOAuth2AuthorizedClientManager(
clientRegistrationRepository, authorizedClientService)
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider)
return authorizedClientManager
}