配置模型
默认配置
OAuth2AuthorizationServerConfiguration
是一个 @Configuration
,为 OAuth2 授权服务器提供最少的默认配置。
OAuth2AuthorizationServerConfiguration
使用 OAuth2AuthorizationServerConfigurer
应用默认配置,并注册一个 SecurityFilterChain
@Bean
,该 @Bean
包含支持 OAuth2 授权服务器的所有基础设施组件。
OAuth2 授权服务器 SecurityFilterChain
@Bean
配置了以下默认协议端点
JWK Set 端点仅在注册了 JWKSource<SecurityContext> @Bean 时才会配置。 |
以下示例展示了如何使用 OAuth2AuthorizationServerConfiguration
应用最少的默认配置
@Configuration
@Import(OAuth2AuthorizationServerConfiguration.class)
public class AuthorizationServerConfig {
@Bean
public RegisteredClientRepository registeredClientRepository() {
List<RegisteredClient> registrations = ...
return new InMemoryRegisteredClientRepository(registrations);
}
@Bean
public JWKSource<SecurityContext> jwkSource() {
RSAKey rsaKey = ...
JWKSet jwkSet = new JWKSet(rsaKey);
return (jwkSelector, securityContext) -> jwkSelector.select(jwkSet);
}
}
authorization_code 授权要求资源所有者经过身份验证。因此,除了默认的 OAuth2 安全配置外,必须配置用户身份验证机制。 |
OpenID Connect 1.0 在默认配置中是禁用的。以下示例展示了如何通过初始化 OidcConfigurer
来启用 OpenID Connect 1.0
@Bean
public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
OAuth2AuthorizationServerConfigurer authorizationServerConfigurer =
OAuth2AuthorizationServerConfigurer.authorizationServer();
http
.securityMatcher(authorizationServerConfigurer.getEndpointsMatcher())
.with(authorizationServerConfigurer, (authorizationServer) ->
authorizationServer
.oidc(Customizer.withDefaults()) // Initialize `OidcConfigurer`
);
return http.build();
}
除了默认协议端点之外,OAuth2 授权服务器 SecurityFilterChain
@Bean
还配置了以下 OpenID Connect 1.0 协议端点
OpenID Connect 1.0 客户端注册端点默认是禁用的,因为许多部署不需要动态客户端注册。 |
OAuth2AuthorizationServerConfiguration.jwtDecoder(JWKSource<SecurityContext>) 是一个便捷的(static )实用方法,可用于注册 JwtDecoder @Bean ,该 @Bean 对于 OpenID Connect 1.0 UserInfo 端点和 OpenID Connect 1.0 客户端注册端点是必需的。 |
以下示例展示了如何注册 JwtDecoder
@Bean
@Bean
public JwtDecoder jwtDecoder(JWKSource<SecurityContext> jwkSource) {
return OAuth2AuthorizationServerConfiguration.jwtDecoder(jwkSource);
}
OAuth2AuthorizationServerConfiguration
的主要目的是提供一种便捷的方式来应用 OAuth2 授权服务器的最少默认配置。然而,在大多数情况下,需要定制配置。
定制配置
OAuth2AuthorizationServerConfigurer
提供了完全定制 OAuth2 授权服务器安全配置的能力。它允许您指定使用的核心组件——例如,RegisteredClientRepository
、OAuth2AuthorizationService
、OAuth2TokenGenerator
等。此外,它允许您定制协议端点的请求处理逻辑——例如,授权端点、设备授权端点、设备验证端点、Token 端点、Token 内省端点 等。
OAuth2AuthorizationServerConfigurer
提供了以下配置选项
@Bean
public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
OAuth2AuthorizationServerConfigurer authorizationServerConfigurer =
OAuth2AuthorizationServerConfigurer.authorizationServer();
http
.securityMatcher(authorizationServerConfigurer.getEndpointsMatcher())
.with(authorizationServerConfigurer, (authorizationServer) ->
authorizationServer
.registeredClientRepository(registeredClientRepository) (1)
.authorizationService(authorizationService) (2)
.authorizationConsentService(authorizationConsentService) (3)
.authorizationServerSettings(authorizationServerSettings) (4)
.tokenGenerator(tokenGenerator) (5)
.clientAuthentication(clientAuthentication -> { }) (6)
.authorizationEndpoint(authorizationEndpoint -> { }) (7)
.deviceAuthorizationEndpoint(deviceAuthorizationEndpoint -> { }) (8)
.deviceVerificationEndpoint(deviceVerificationEndpoint -> { }) (9)
.tokenEndpoint(tokenEndpoint -> { }) (10)
.tokenIntrospectionEndpoint(tokenIntrospectionEndpoint -> { }) (11)
.tokenRevocationEndpoint(tokenRevocationEndpoint -> { }) (12)
.authorizationServerMetadataEndpoint(authorizationServerMetadataEndpoint -> { }) (13)
.oidc(oidc -> oidc
.providerConfigurationEndpoint(providerConfigurationEndpoint -> { }) (14)
.logoutEndpoint(logoutEndpoint -> { }) (15)
.userInfoEndpoint(userInfoEndpoint -> { }) (16)
.clientRegistrationEndpoint(clientRegistrationEndpoint -> { }) (17)
)
);
return http.build();
}
1 | registeredClientRepository() :用于管理新客户端和现有客户端的 RegisteredClientRepository (必需)。 |
2 | authorizationService() :用于管理新授权和现有授权的 OAuth2AuthorizationService 。 |
3 | authorizationConsentService() :用于管理新授权同意和现有授权同意的 OAuth2AuthorizationConsentService 。 |
4 | authorizationServerSettings() :用于定制 OAuth2 授权服务器配置设置的 AuthorizationServerSettings (必需)。 |
5 | tokenGenerator() :用于生成 OAuth2 授权服务器支持的 Token 的 OAuth2TokenGenerator 。 |
6 | clientAuthentication() :OAuth2 客户端身份验证的配置器。 |
7 | authorizationEndpoint() :OAuth2 授权端点的配置器。 |
8 | deviceAuthorizationEndpoint() :OAuth2 设备授权端点的配置器。 |
9 | deviceVerificationEndpoint() :OAuth2 设备验证端点的配置器。 |
10 | tokenEndpoint() :OAuth2 Token 端点的配置器。 |
11 | tokenIntrospectionEndpoint() :OAuth2 Token 内省端点的配置器。 |
12 | tokenRevocationEndpoint() :OAuth2 Token 撤销端点的配置器。 |
13 | authorizationServerMetadataEndpoint() :OAuth2 授权服务器元数据端点的配置器。 |
14 | providerConfigurationEndpoint() :OpenID Connect 1.0 Provider 配置端点的配置器。 |
15 | logoutEndpoint() :OpenID Connect 1.0 Logout 端点的配置器。 |
16 | userInfoEndpoint() :OpenID Connect 1.0 UserInfo 端点的配置器。 |
17 | clientRegistrationEndpoint() :OpenID Connect 1.0 客户端注册端点的配置器。 |
配置授权服务器设置
AuthorizationServerSettings
包含 OAuth2 授权服务器的配置设置。它指定协议端点的 URI
以及 Issuer Identifier。协议端点的默认 URI
如下
public final class AuthorizationServerSettings extends AbstractSettings {
...
public static Builder builder() {
return new Builder()
.authorizationEndpoint("/oauth2/authorize")
.deviceAuthorizationEndpoint("/oauth2/device_authorization")
.deviceVerificationEndpoint("/oauth2/device_verification")
.tokenEndpoint("/oauth2/token")
.tokenIntrospectionEndpoint("/oauth2/introspect")
.tokenRevocationEndpoint("/oauth2/revoke")
.jwkSetEndpoint("/oauth2/jwks")
.oidcLogoutEndpoint("/connect/logout")
.oidcUserInfoEndpoint("/userinfo")
.oidcClientRegistrationEndpoint("/connect/register");
}
...
}
AuthorizationServerSettings 是一个必需的组件。 |
@Import(OAuth2AuthorizationServerConfiguration.class) 会自动注册一个 AuthorizationServerSettings @Bean ,如果尚未提供的话。 |
以下示例展示了如何定制配置设置并注册一个 AuthorizationServerSettings
@Bean
@Bean
public AuthorizationServerSettings authorizationServerSettings() {
return AuthorizationServerSettings.builder()
.issuer("https://example.com")
.authorizationEndpoint("/oauth2/v1/authorize")
.deviceAuthorizationEndpoint("/oauth2/v1/device_authorization")
.deviceVerificationEndpoint("/oauth2/v1/device_verification")
.tokenEndpoint("/oauth2/v1/token")
.tokenIntrospectionEndpoint("/oauth2/v1/introspect")
.tokenRevocationEndpoint("/oauth2/v1/revoke")
.jwkSetEndpoint("/oauth2/v1/jwks")
.oidcLogoutEndpoint("/connect/v1/logout")
.oidcUserInfoEndpoint("/connect/v1/userinfo")
.oidcClientRegistrationEndpoint("/connect/v1/register")
.build();
}
AuthorizationServerContext
是一个上下文对象,持有授权服务器运行时环境的信息。它提供对 AuthorizationServerSettings
和“当前”Issuer Identifier 的访问。
如果 Issuer Identifier 未在 AuthorizationServerSettings.builder().issuer(String) 中配置,则会从当前请求中解析。 |
通过 AuthorizationServerContextHolder 可以访问 AuthorizationServerContext ,后者使用 ThreadLocal 将其与当前请求线程关联。 |
配置客户端身份验证
OAuth2ClientAuthenticationConfigurer
提供了定制 OAuth2 客户端身份验证的能力。它定义了扩展点,允许您定制客户端身份验证请求的预处理、主要处理和后处理逻辑。
OAuth2ClientAuthenticationConfigurer
提供了以下配置选项
@Bean
public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
OAuth2AuthorizationServerConfigurer authorizationServerConfigurer =
OAuth2AuthorizationServerConfigurer.authorizationServer();
http
.securityMatcher(authorizationServerConfigurer.getEndpointsMatcher())
.with(authorizationServerConfigurer, (authorizationServer) ->
authorizationServer
.clientAuthentication(clientAuthentication ->
clientAuthentication
.authenticationConverter(authenticationConverter) (1)
.authenticationConverters(authenticationConvertersConsumer) (2)
.authenticationProvider(authenticationProvider) (3)
.authenticationProviders(authenticationProvidersConsumer) (4)
.authenticationSuccessHandler(authenticationSuccessHandler) (5)
.errorResponseHandler(errorResponseHandler) (6)
)
);
return http.build();
}
1 | authenticationConverter() :添加一个 AuthenticationConverter (预处理器),用于尝试从 HttpServletRequest 提取客户端凭据并转换为 OAuth2ClientAuthenticationToken 实例。 |
2 | authenticationConverters() :设置 Consumer ,提供对默认和(可选)添加的 AuthenticationConverter 列表的访问,允许添加、删除或定制特定的 AuthenticationConverter 。 |
3 | authenticationProvider() :添加一个 AuthenticationProvider (主要处理器),用于对 OAuth2ClientAuthenticationToken 进行身份验证。 |
4 | authenticationProviders() :设置 Consumer ,提供对默认和(可选)添加的 AuthenticationProvider 列表的访问,允许添加、删除或定制特定的 AuthenticationProvider 。 |
5 | authenticationSuccessHandler() :用于处理成功客户端身份验证并将 OAuth2ClientAuthenticationToken 关联到 SecurityContext 的 AuthenticationSuccessHandler (后处理器)。 |
6 | errorResponseHandler() :用于处理失败客户端身份验证并返回 OAuth2Error 响应的 AuthenticationFailureHandler (后处理器)。 |
OAuth2ClientAuthenticationConfigurer
配置 OAuth2ClientAuthenticationFilter
并将其注册到 OAuth2 授权服务器 SecurityFilterChain
@Bean
。OAuth2ClientAuthenticationFilter
是处理客户端身份验证请求的 Filter
。
默认情况下,OAuth2 Token 端点、OAuth2 Token 内省端点和 OAuth2 Token 撤销端点需要客户端身份验证。支持的客户端身份验证方法有 client_secret_basic
、client_secret_post
、private_key_jwt
、client_secret_jwt
、tls_client_auth
、self_signed_tls_client_auth
和 none
(公共客户端)。
OAuth2ClientAuthenticationFilter
配置了以下默认设置
-
AuthenticationConverter
— 一个DelegatingAuthenticationConverter
,由JwtClientAssertionAuthenticationConverter
、X509ClientCertificateAuthenticationConverter
、ClientSecretBasicAuthenticationConverter
、ClientSecretPostAuthenticationConverter
和PublicClientAuthenticationConverter
组成。 -
AuthenticationManager
— 一个AuthenticationManager
,由JwtClientAssertionAuthenticationProvider
、X509ClientCertificateAuthenticationProvider
、ClientSecretAuthenticationProvider
和PublicClientAuthenticationProvider
组成。 -
AuthenticationSuccessHandler
— 一个内部实现,用于将“已认证的”OAuth2ClientAuthenticationToken
(当前Authentication
)关联到SecurityContext
。 -
AuthenticationFailureHandler
— 一个内部实现,使用与OAuth2AuthenticationException
关联的OAuth2Error
返回 OAuth2 错误响应。
定制 Jwt Client Assertion 验证
JwtClientAssertionDecoderFactory.DEFAULT_JWT_VALIDATOR_FACTORY
是默认的工厂,它为指定的 RegisteredClient
提供一个 OAuth2TokenValidator<Jwt>
,用于验证 Jwt client assertion 的 iss
、sub
、aud
、exp
和 nbf
Claims。
JwtClientAssertionDecoderFactory
提供了通过向 setJwtValidatorFactory()
提供类型为 Function<RegisteredClient, OAuth2TokenValidator<Jwt>>
的自定义工厂来覆盖默认 Jwt client assertion 验证的能力。
JwtClientAssertionDecoderFactory 是 JwtClientAssertionAuthenticationProvider 使用的默认 JwtDecoderFactory ,它为指定的 RegisteredClient 提供一个 JwtDecoder ,用于在 OAuth2 客户端身份验证期间验证 Jwt 持有者令牌。 |
定制 JwtClientAssertionDecoderFactory
的一个常见用例是在 Jwt client assertion 中验证额外的 Claims。
以下示例展示了如何使用定制的 JwtClientAssertionDecoderFactory
配置 JwtClientAssertionAuthenticationProvider
,该工厂验证 Jwt client assertion 中的一个附加 Claim
@Bean
public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
OAuth2AuthorizationServerConfigurer authorizationServerConfigurer =
OAuth2AuthorizationServerConfigurer.authorizationServer();
http
.securityMatcher(authorizationServerConfigurer.getEndpointsMatcher())
.with(authorizationServerConfigurer, (authorizationServer) ->
authorizationServer
.clientAuthentication(clientAuthentication ->
clientAuthentication
.authenticationProviders(configureJwtClientAssertionValidator())
)
);
return http.build();
}
private Consumer<List<AuthenticationProvider>> configureJwtClientAssertionValidator() {
return (authenticationProviders) ->
authenticationProviders.forEach((authenticationProvider) -> {
if (authenticationProvider instanceof JwtClientAssertionAuthenticationProvider) {
// Customize JwtClientAssertionDecoderFactory
JwtClientAssertionDecoderFactory jwtDecoderFactory = new JwtClientAssertionDecoderFactory();
Function<RegisteredClient, OAuth2TokenValidator<Jwt>> jwtValidatorFactory = (registeredClient) ->
new DelegatingOAuth2TokenValidator<>(
// Use default validators
JwtClientAssertionDecoderFactory.DEFAULT_JWT_VALIDATOR_FACTORY.apply(registeredClient),
// Add custom validator
new JwtClaimValidator<>("claim", "value"::equals));
jwtDecoderFactory.setJwtValidatorFactory(jwtValidatorFactory);
((JwtClientAssertionAuthenticationProvider) authenticationProvider)
.setJwtDecoderFactory(jwtDecoderFactory);
}
});
}
定制 Mutual-TLS 客户端身份验证
X509ClientCertificateAuthenticationProvider
用于验证在 OAuth2 客户端身份验证期间使用 ClientAuthenticationMethod.TLS_CLIENT_AUTH
或 ClientAuthenticationMethod.SELF_SIGNED_TLS_CLIENT_AUTH
方法时接收到的客户端 X509Certificate
链。它还包含一个“证书验证器”,用于在 TLS 握手成功完成后验证客户端 X509Certificate
的内容。
PKI Mutual-TLS 方法
对于 PKI Mutual-TLS(ClientAuthenticationMethod.TLS_CLIENT_AUTH
)方法,证书验证器的默认实现根据设置 RegisteredClient.getClientSettings.getX509CertificateSubjectDN()
验证客户端 X509Certificate
的主题可分辨名称。
如果您需要验证客户端 X509Certificate
的其他属性,例如 Subject Alternative Name (SAN) 条目,以下示例展示了如何使用证书验证器的自定义实现配置 X509ClientCertificateAuthenticationProvider
@Bean
public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
OAuth2AuthorizationServerConfigurer authorizationServerConfigurer =
OAuth2AuthorizationServerConfigurer.authorizationServer();
http
.securityMatcher(authorizationServerConfigurer.getEndpointsMatcher())
.with(authorizationServerConfigurer, (authorizationServer) ->
authorizationServer
.clientAuthentication(clientAuthentication ->
clientAuthentication
.authenticationProviders(configureX509ClientCertificateVerifier())
)
);
return http.build();
}
private Consumer<List<AuthenticationProvider>> configureX509ClientCertificateVerifier() {
return (authenticationProviders) ->
authenticationProviders.forEach((authenticationProvider) -> {
if (authenticationProvider instanceof X509ClientCertificateAuthenticationProvider) {
Consumer<OAuth2ClientAuthenticationContext> certificateVerifier = (clientAuthenticationContext) -> {
OAuth2ClientAuthenticationToken clientAuthentication = clientAuthenticationContext.getAuthentication();
RegisteredClient registeredClient = clientAuthenticationContext.getRegisteredClient();
X509Certificate[] clientCertificateChain = (X509Certificate[]) clientAuthentication.getCredentials();
X509Certificate clientCertificate = clientCertificateChain[0];
// TODO Verify Subject Alternative Name (SAN) entry
};
((X509ClientCertificateAuthenticationProvider) authenticationProvider)
.setCertificateVerifier(certificateVerifier);
}
});
}
自签名证书 Mutual-TLS 方法
对于自签名证书 Mutual-TLS(ClientAuthenticationMethod.SELF_SIGNED_TLS_CLIENT_AUTH
)方法,证书验证器的默认实现将使用设置 RegisteredClient.getClientSettings.getJwkSetUrl()
检索客户端的 JSON Web Key Set,并期望找到与 TLS 握手期间接收到的客户端 X509Certificate
匹配的项。
RegisteredClient.getClientSettings.getJwkSetUrl() 设置用于通过 JSON Web Key (JWK) Set 检索客户端的证书。证书由集合中单个 JWK 的 x5c 参数表示。 |
客户端证书绑定的访问令牌
当在 Token 端点使用 Mutual-TLS 客户端身份验证时,授权服务器能够将颁发的访问令牌绑定到客户端的 X509Certificate
。绑定是通过计算客户端 X509Certificate
的 SHA-256 指纹,并将指纹与访问令牌关联来完成的。例如,一个 JWT 访问令牌会在顶级 cnf
(confirmation method)Claim 中包含一个 x5t#S256
Claim,其中包含 X509Certificate
指纹。
将访问令牌绑定到客户端的 X509Certificate
提供了在访问受保护资源时实现持有者证明机制的能力。例如,受保护资源会获取在 Mutual-TLS 身份验证期间使用的客户端 X509Certificate
,然后验证证书指纹是否与访问令牌关联的 x5t#S256
Claim 匹配。
以下示例展示了如何为客户端启用证书绑定的访问令牌
RegisteredClient mtlsClient = RegisteredClient.withId(UUID.randomUUID().toString())
.clientId("mtls-client")
.clientAuthenticationMethod(ClientAuthenticationMethod.TLS_CLIENT_AUTH)
.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
.scope("scope-a")
.clientSettings(
ClientSettings.builder()
.x509CertificateSubjectDN("CN=mtls-client,OU=Spring Samples,O=Spring,C=US")
.build()
)
.tokenSettings(
TokenSettings.builder()
.x509CertificateBoundAccessTokens(true)
.build()
)
.build();