核心型号/组件
已注册客户端
一个RegisteredClient是在授权服务器中注册的客户端的表示。
客户端必须先向授权服务器注册,然后才能启动授权授予流,例如authorization_code或client_credentials.
在客户端注册期间,将为客户端分配一个唯一的客户端标识符、(可选)客户端密码(取决于客户端类型)以及与其唯一客户端标识符关联的元数据。 客户端的元数据范围可以从面向人类的显示字符串 ((例如客户端名称) 到特定于协议流的项 (例如有效重定向 URI 的列表) 。
| Spring Security 的 OAuth2 客户端支持中相应的客户端注册模型是 ClientRegistration。 |
客户端的主要目的是请求访问受保护的资源。 客户端首先通过向授权服务器进行身份验证并提供授权授予来请求访问Tokens。 授权服务器对客户端和授权授予进行身份验证,如果它们有效,则颁发访问Tokens。 客户端现在可以通过提供访问Tokens从资源服务器请求受保护的资源。
以下示例演示如何配置RegisteredClient允许执行authorization_code授权流以请求访问Tokens:
RegisteredClient registeredClient = RegisteredClient.withId(UUID.randomUUID().toString())
.clientId("client-a")
.clientSecret("{noop}secret") (1)
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
.redirectUri("http://127.0.0.1:8080/authorized")
.scope("scope-a")
.clientSettings(ClientSettings.builder().requireAuthorizationConsent(true).build())
.build();
| 1 | {noop}表示PasswordEncoderid 用于 Spring Security 的 NoOpPasswordEncoder。 |
Spring Security 的 OAuth2 客户端支持中的相应配置是:
spring:
security:
oauth2:
client:
registration:
client-a:
provider: spring
client-id: client-a
client-secret: secret
authorization-grant-type: authorization_code
redirect-uri: "http://127.0.0.1:8080/authorized"
scope: scope-a
provider:
spring:
issuer-uri: http://localhost:9000
一个RegisteredClient具有与其唯一客户端标识符关联的元数据(属性),定义如下:
public class RegisteredClient implements Serializable {
private String id; (1)
private String clientId; (2)
private Instant clientIdIssuedAt; (3)
private String clientSecret; (4)
private Instant clientSecretExpiresAt; (5)
private String clientName; (6)
private Set<ClientAuthenticationMethod> clientAuthenticationMethods; (7)
private Set<AuthorizationGrantType> authorizationGrantTypes; (8)
private Set<String> redirectUris; (9)
private Set<String> postLogoutRedirectUris; (10)
private Set<String> scopes; (11)
private ClientSettings clientSettings; (12)
private TokenSettings tokenSettings; (13)
...
}
| 1 | id:唯一标识RegisteredClient. |
| 2 | clientId:客户端标识符。 |
| 3 | clientIdIssuedAt:发出客户端标识符的时间。 |
| 4 | clientSecret:客户端的秘密。该值应使用 Spring Security 的 PasswordEncoder 进行编码。 |
| 5 | clientSecretExpiresAt:客户端密钥过期的时间。 |
| 6 | clientName:用于客户端的描述性名称。该名称可能在某些情况下使用,例如在同意页面中显示客户端名称时。 |
| 7 | clientAuthenticationMethods:客户端可以使用的身份验证方法。支持的值是client_secret_basic,client_secret_post,private_key_jwt,client_secret_jwt和none (公共客户)。 |
| 8 | authorizationGrantTypes:客户端可以使用的授权授予类型。支持的值是authorization_code,client_credentials,refresh_token,urn:ietf:params:oauth:grant-type:device_code和urn:ietf:params:oauth:grant-type:token-exchange. |
| 9 | redirectUris:客户端可以在基于重定向的流中使用的已注册重定向 URI,例如authorization_code授予。 |
| 10 | postLogoutRedirectUris:客户端可用于注销的注销后重定向 URI。 |
| 11 | scopes:允许客户端请求的范围。 |
| 12 | clientSettings:客户端的自定义设置 - 例如,需要 PKCE、需要授权同意等。 |
| 13 | tokenSettings:颁发给客户端的 OAuth2 Tokens的自定义设置,例如,访问/刷新Tokens生存时间、重用刷新Tokens等。 |
已注册客户端存储库
这RegisteredClientRepository是可以注册新客户端和查询现有客户端的核心组件。
当遵循特定协议流时,其他组件会使用它,例如客户端身份验证、授权授予处理、Tokens自检、动态客户端注册等。
提供的实现RegisteredClientRepository是InMemoryRegisteredClientRepository和JdbcRegisteredClientRepository.
这InMemoryRegisteredClientRepository实施存储RegisteredClient实例,建议仅在开发和测试期间使用。JdbcRegisteredClientRepository是一个持久的 JDBC 实现RegisteredClient实例,使用JdbcOperations.
这RegisteredClientRepository是必需组件。 |
以下示例演示如何注册RegisteredClientRepository @Bean:
@Bean
public RegisteredClientRepository registeredClientRepository() {
List<RegisteredClient> registrations = ...
return new InMemoryRegisteredClientRepository(registrations);
}
或者,您可以配置RegisteredClientRepository通过OAuth2AuthorizationServerConfigurer:
@Bean
public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
OAuth2AuthorizationServerConfigurer authorizationServerConfigurer =
OAuth2AuthorizationServerConfigurer.authorizationServer();
http
.securityMatcher(authorizationServerConfigurer.getEndpointsMatcher())
.with(authorizationServerConfigurer, (authorizationServer) ->
authorizationServer
.registeredClientRepository(registeredClientRepository)
)
...
return http.build();
}
这OAuth2AuthorizationServerConfigurer在同时应用多个配置选项时很有用。 |
OAuth2授权
| Spring Security 的 OAuth2 客户端支持中相应的授权模型是 OAuth2AuthorizedClient。 |
成功完成授权授予流后,将OAuth2Authorization创建并关联一个OAuth2AccessToken、一个(可选)OAuth2RefreshToken,以及特定于已执行授权授权类型的其他状态。
这OAuth2Token与OAuth2Authorization根据授权授予类型而有所不同。
对于 OAuth2 authorization_code授权,一个OAuth2AuthorizationCode一OAuth2AccessToken和(可选)OAuth2RefreshToken是关联的。
对于 OpenID Connect 1.0 authorization_code授权,一个OAuth2AuthorizationCode一OidcIdToken一OAuth2AccessToken和(可选)OAuth2RefreshToken是关联的。
对于 OAuth2 client_credentials 授权,只有OAuth2AccessToken是关联的。
OAuth2Authorization其属性定义如下:
public class OAuth2Authorization implements Serializable {
private String id; (1)
private String registeredClientId; (2)
private String principalName; (3)
private AuthorizationGrantType authorizationGrantType; (4)
private Set<String> authorizedScopes; (5)
private Map<Class<? extends OAuth2Token>, Token<?>> tokens; (6)
private Map<String, Object> attributes; (7)
...
}
| 1 | id:唯一标识OAuth2Authorization. |
| 2 | registeredClientId:唯一标识 RegisteredClient 的 ID。 |
| 3 | principalName:资源所有者(或客户端)的主体名称。 |
| 4 | authorizationGrantType:这AuthorizationGrantType使用。 |
| 5 | authorizedScopes:这Set为客户授权的范围。 |
| 6 | tokens:这OAuth2Token特定于已执行授权授权类型的实例(和关联的元数据)。 |
| 7 | attributes:特定于已执行授权授权类型的其他属性 - 例如,已验证的Principal,OAuth2AuthorizationRequest,等。 |
OAuth2Authorization及其相关的OAuth2Token实例有固定的生命周期。
新发行的OAuth2Token处于活动状态,并在过期或失效(撤销)时变为非活动状态。
这OAuth2Authorization当所有关联的OAuth2Token实例处于非活动状态。
每OAuth2Token在OAuth2Authorization.Token,它为isExpired(),isInvalidated()和isActive().
OAuth2Authorization.Token还提供getClaims(),它返回与OAuth2Token.
OAuth2授权服务
这OAuth2AuthorizationService是存储新授权和查询现有授权的核心组件。
当遵循特定协议流时,其他组件会使用它,例如,客户端身份验证、授权授权处理、Tokens自省、Tokens吊销、动态客户端注册等。
提供的实现OAuth2AuthorizationService是InMemoryOAuth2AuthorizationService和JdbcOAuth2AuthorizationService.
这InMemoryOAuth2AuthorizationService实施存储OAuth2Authorization实例,建议仅在开发和测试期间使用。JdbcOAuth2AuthorizationService是一个持久的 JDBC 实现OAuth2Authorization实例,使用JdbcOperations.
这OAuth2AuthorizationService是一个 OPTIONAL 组件,默认为InMemoryOAuth2AuthorizationService. |
以下示例演示如何注册OAuth2AuthorizationService @Bean:
@Bean
public OAuth2AuthorizationService authorizationService() {
return new InMemoryOAuth2AuthorizationService();
}
或者,您可以配置OAuth2AuthorizationService通过OAuth2AuthorizationServerConfigurer:
@Bean
public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
OAuth2AuthorizationServerConfigurer authorizationServerConfigurer =
OAuth2AuthorizationServerConfigurer.authorizationServer();
http
.securityMatcher(authorizationServerConfigurer.getEndpointsMatcher())
.with(authorizationServerConfigurer, (authorizationServer) ->
authorizationServer
.authorizationService(authorizationService)
)
...
return http.build();
}
这OAuth2AuthorizationServerConfigurer在同时应用多个配置选项时很有用。 |
OAuth2Authorization同意
一OAuth2AuthorizationConsent是来自 OAuth2 授权请求流的授权“同意”(决定)的表示形式,例如,authorization_code授予,它持有资源所有者授予客户端的权限。
在授权对客户端的访问时,资源所有者只能授予客户端请求的权限的子集。典型的用例是authorization_code授予流,其中客户端请求范围,资源所有者授予(或拒绝)对请求范围的访问权限。
OAuth2 授权请求流完成后,一个OAuth2AuthorizationConsent创建(或更新)并将授予的权限与客户机和资源所有者相关联。
OAuth2AuthorizationConsent其属性定义如下:
public final class OAuth2AuthorizationConsent implements Serializable {
private final String registeredClientId; (1)
private final String principalName; (2)
private final Set<GrantedAuthority> authorities; (3)
...
}
| 1 | registeredClientId:唯一标识 RegisteredClient 的 ID。 |
| 2 | principalName:资源所有者的主体名称。 |
| 3 | authorities:资源所有者授予客户端的权限。权限可以表示范围、声明、权限、角色等。 |
OAuth2AuthorizationConsentService
这OAuth2AuthorizationConsentService是存储新授权同意和查询现有授权同意的核心组件。它主要由实现 OAuth2 授权请求流的组件使用,例如authorization_code授予。
提供的实现OAuth2AuthorizationConsentService是InMemoryOAuth2AuthorizationConsentService和JdbcOAuth2AuthorizationConsentService.
这InMemoryOAuth2AuthorizationConsentService实施存储OAuth2AuthorizationConsent实例在内存中,建议仅用于开发和测试。JdbcOAuth2AuthorizationConsentService是一个持久的 JDBC 实现OAuth2AuthorizationConsent实例,使用JdbcOperations.
这OAuth2AuthorizationConsentService是一个 OPTIONAL 组件,默认为InMemoryOAuth2AuthorizationConsentService. |
以下示例演示如何注册OAuth2AuthorizationConsentService @Bean:
@Bean
public OAuth2AuthorizationConsentService authorizationConsentService() {
return new InMemoryOAuth2AuthorizationConsentService();
}
或者,您可以配置OAuth2AuthorizationConsentService通过OAuth2AuthorizationServerConfigurer:
@Bean
public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
OAuth2AuthorizationServerConfigurer authorizationServerConfigurer =
OAuth2AuthorizationServerConfigurer.authorizationServer();
http
.securityMatcher(authorizationServerConfigurer.getEndpointsMatcher())
.with(authorizationServerConfigurer, (authorizationServer) ->
authorizationServer
.authorizationConsentService(authorizationConsentService)
)
...
return http.build();
}
这OAuth2AuthorizationServerConfigurer在同时应用多个配置选项时很有用。 |
OAuth2Token上下文
一OAuth2TokenContext是一个上下文对象,其中包含与OAuth2Token并由 OAuth2TokenGenerator 和 OAuth2TokenCustomizer 使用。
OAuth2TokenContext提供以下访问器:
public interface OAuth2TokenContext extends Context {
default RegisteredClient getRegisteredClient() ... (1)
default <T extends Authentication> T getPrincipal() ... (2)
default AuthorizationServerContext getAuthorizationServerContext() ... (3)
@Nullable
default OAuth2Authorization getAuthorization() ... (4)
default Set<String> getAuthorizedScopes() ... (5)
default OAuth2TokenType getTokenType() ... (6)
default AuthorizationGrantType getAuthorizationGrantType() ... (7)
default <T extends Authentication> T getAuthorizationGrant() ... (8)
...
}
| 1 | getRegisteredClient():与授权授予关联的 RegisteredClient。 |
| 2 | getPrincipal():这Authentication资源所有者(或客户端)的实例。 |
| 3 | getAuthorizationServerContext():这AuthorizationServerContext保存授权服务器运行时环境信息的对象。 |
| 4 | getAuthorization():与授权授予关联的 OAuth2Authorization。 |
| 5 | getAuthorizedScopes():为客户端授权的范围。 |
| 6 | getTokenType():这OAuth2TokenType生成。支持的值是code,access_token,refresh_token和id_token. |
| 7 | getAuthorizationGrantType():这AuthorizationGrantType与授权授予相关联。 |
| 8 | getAuthorizationGrant():这Authentication实例AuthenticationProvider处理授权授予。 |
OAuth2Token生成器
一OAuth2TokenGenerator负责生成OAuth2Token从提供的 OAuth2TokenContext 中包含的信息。
这OAuth2Token生成主要取决于OAuth2TokenType在OAuth2TokenContext.
例如,当value为OAuth2TokenType是:
-
code然后OAuth2AuthorizationCode生成。 -
access_token然后OAuth2AccessToken生成。 -
refresh_token然后OAuth2RefreshToken生成。 -
id_token然后OidcIdToken生成。
此外,生成的格式OAuth2AccessToken根据TokenSettings.getAccessTokenFormat()为 RegisteredClient 配置。
如果格式为OAuth2TokenFormat.SELF_CONTAINED(默认值),然后Jwt生成。
如果格式为OAuth2TokenFormat.REFERENCE,则生成一个“不透明”Tokens。
最后,如果生成的OAuth2Token有一套主张和手段ClaimAccessor,则可从 OAuth2Authorization.Token.getClaims() 访问声明。
这OAuth2TokenGenerator主要由实现授权授予处理的组件使用,例如authorization_code,client_credentials和refresh_token.
提供的实现是OAuth2AccessTokenGenerator,OAuth2RefreshTokenGenerator和JwtGenerator.
这OAuth2AccessTokenGenerator生成一个“不透明”(OAuth2TokenFormat.REFERENCE) 访问Tokens,以及JwtGenerator生成一个Jwt (OAuth2TokenFormat.SELF_CONTAINED).
这OAuth2TokenGenerator是一个 OPTIONAL 组件,默认为DelegatingOAuth2TokenGenerator由一个OAuth2AccessTokenGenerator和OAuth2RefreshTokenGenerator. |
如果JwtEncoder @Bean或JWKSource<SecurityContext> @Bean注册,则JwtGenerator另外组成在DelegatingOAuth2TokenGenerator. |
这OAuth2TokenGenerator提供了极大的灵活性,因为它可以支持任何自定义Tokens格式access_token和refresh_token.
以下示例演示如何注册OAuth2TokenGenerator @Bean:
@Bean
public OAuth2TokenGenerator<?> tokenGenerator() {
JwtEncoder jwtEncoder = ...
JwtGenerator jwtGenerator = new JwtGenerator(jwtEncoder);
OAuth2AccessTokenGenerator accessTokenGenerator = new OAuth2AccessTokenGenerator();
OAuth2RefreshTokenGenerator refreshTokenGenerator = new OAuth2RefreshTokenGenerator();
return new DelegatingOAuth2TokenGenerator(
jwtGenerator, accessTokenGenerator, refreshTokenGenerator);
}
或者,您可以配置OAuth2TokenGenerator通过OAuth2AuthorizationServerConfigurer:
@Bean
public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
OAuth2AuthorizationServerConfigurer authorizationServerConfigurer =
OAuth2AuthorizationServerConfigurer.authorizationServer();
http
.securityMatcher(authorizationServerConfigurer.getEndpointsMatcher())
.with(authorizationServerConfigurer, (authorizationServer) ->
authorizationServer
.tokenGenerator(tokenGenerator)
)
...
return http.build();
}
这OAuth2AuthorizationServerConfigurer在同时应用多个配置选项时很有用。 |
OAuth2Token定制器
一OAuth2TokenCustomizer提供了自定义OAuth2Token,可在提供的 OAuth2TokenContext 中访问。
OAuth2TokenGenerator 使用它来自定义OAuth2Token在生成之前。
一OAuth2TokenCustomizer<OAuth2TokenClaimsContext>使用泛型类型OAuth2TokenClaimsContext (implements OAuth2TokenContext) 提供了自定义“不透明”声明的能力OAuth2AccessToken.OAuth2TokenClaimsContext.getClaims()提供对OAuth2TokenClaimsSet.Builder,允许添加、替换和删除声明。
以下示例演示如何实现OAuth2TokenCustomizer<OAuth2TokenClaimsContext>并使用OAuth2AccessTokenGenerator:
@Bean
public OAuth2TokenGenerator<?> tokenGenerator() {
JwtEncoder jwtEncoder = ...
JwtGenerator jwtGenerator = new JwtGenerator(jwtEncoder);
OAuth2AccessTokenGenerator accessTokenGenerator = new OAuth2AccessTokenGenerator();
accessTokenGenerator.setAccessTokenCustomizer(accessTokenCustomizer());
OAuth2RefreshTokenGenerator refreshTokenGenerator = new OAuth2RefreshTokenGenerator();
return new DelegatingOAuth2TokenGenerator(
jwtGenerator, accessTokenGenerator, refreshTokenGenerator);
}
@Bean
public OAuth2TokenCustomizer<OAuth2TokenClaimsContext> accessTokenCustomizer() {
return context -> {
OAuth2TokenClaimsSet.Builder claims = context.getClaims();
// Customize claims
};
}
如果OAuth2TokenGenerator未作为@Bean或未通过OAuth2AuthorizationServerConfigurer一OAuth2TokenCustomizer<OAuth2TokenClaimsContext> @Bean将自动配置OAuth2AccessTokenGenerator. |
一OAuth2TokenCustomizer<JwtEncodingContext>使用泛型类型JwtEncodingContext (implements OAuth2TokenContext) 提供了自定义Jwt.JwtEncodingContext.getJwsHeader()提供对JwsHeader.Builder,允许添加、替换和删除标头。JwtEncodingContext.getClaims()提供对JwtClaimsSet.Builder,允许添加、替换和删除声明。
以下示例演示如何实现OAuth2TokenCustomizer<JwtEncodingContext>并使用JwtGenerator:
@Bean
public OAuth2TokenGenerator<?> tokenGenerator() {
JwtEncoder jwtEncoder = ...
JwtGenerator jwtGenerator = new JwtGenerator(jwtEncoder);
jwtGenerator.setJwtCustomizer(jwtCustomizer());
OAuth2AccessTokenGenerator accessTokenGenerator = new OAuth2AccessTokenGenerator();
OAuth2RefreshTokenGenerator refreshTokenGenerator = new OAuth2RefreshTokenGenerator();
return new DelegatingOAuth2TokenGenerator(
jwtGenerator, accessTokenGenerator, refreshTokenGenerator);
}
@Bean
public OAuth2TokenCustomizer<JwtEncodingContext> jwtCustomizer() {
return context -> {
JwsHeader.Builder headers = context.getJwsHeader();
JwtClaimsSet.Builder claims = context.getClaims();
if (context.getTokenType().equals(OAuth2TokenType.ACCESS_TOKEN)) {
// Customize headers/claims for access_token
} else if (context.getTokenType().getValue().equals(OidcParameterNames.ID_TOKEN)) {
// Customize headers/claims for id_token
}
};
}
如果OAuth2TokenGenerator未作为@Bean或未通过OAuth2AuthorizationServerConfigurer一OAuth2TokenCustomizer<JwtEncodingContext> @Bean将自动配置JwtGenerator. |
| 有关演示如何自定义 ID Tokens的示例,请参阅指南作方法:自定义 OpenID Connect 1.0 UserInfo 响应。 |
会话注册表
如果启用了 OpenID Connect 1.0,则SessionRegistry实例用于跟踪经过身份验证的会话。
这SessionRegistry由默认实现的SessionAuthenticationStrategy与 OAuth2 授权终结点相关联,用于注册新的经过身份验证的会话。
如果SessionRegistry @Bean未注册,则默认实现SessionRegistryImpl将被使用。 |
如果SessionRegistry @Bean已注册,并且是SessionRegistryImpl一个HttpSessionEventPublisher @Bean 也应该注册,因为它负责通知SessionRegistryImpl会话生命周期事件,例如SessionDestroyedEvent,以提供删除SessionInformation实例。 |
当最终用户请求注销时,OpenID Connect 1.0 注销端点使用SessionRegistry查找SessionInformation关联到经过身份验证的最终用户以执行注销。
如果正在使用 Spring Security 的并发会话控制功能,建议注册一个SessionRegistry @Bean以确保它在 Spring Security 的并发会话控制和 Spring Authorization Server 的注销功能之间共享。
以下示例演示如何注册SessionRegistry @Bean和HttpSessionEventPublisher @Bean(要求SessionRegistryImpl):
@Bean
public SessionRegistry sessionRegistry() {
return new SessionRegistryImpl();
}
@Bean
public HttpSessionEventPublisher httpSessionEventPublisher() {
return new HttpSessionEventPublisher();
}