配置模型

默认配置

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 授权服务器安全配置的能力。它允许您指定使用的核心组件——例如,RegisteredClientRepositoryOAuth2AuthorizationServiceOAuth2TokenGenerator 等。此外,它允许您定制协议端点的请求处理逻辑——例如,授权端点设备授权端点设备验证端点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 关联到 SecurityContextAuthenticationSuccessHandler后处理器)。
6 errorResponseHandler():用于处理失败客户端身份验证并返回 OAuth2Error 响应AuthenticationFailureHandler后处理器)。

OAuth2ClientAuthenticationConfigurer 配置 OAuth2ClientAuthenticationFilter 并将其注册到 OAuth2 授权服务器 SecurityFilterChain @BeanOAuth2ClientAuthenticationFilter 是处理客户端身份验证请求的 Filter

默认情况下,OAuth2 Token 端点、OAuth2 Token 内省端点和 OAuth2 Token 撤销端点需要客户端身份验证。支持的客户端身份验证方法有 client_secret_basicclient_secret_postprivate_key_jwtclient_secret_jwttls_client_authself_signed_tls_client_authnone(公共客户端)。

OAuth2ClientAuthenticationFilter 配置了以下默认设置

  • AuthenticationConverter — 一个 DelegatingAuthenticationConverter,由 JwtClientAssertionAuthenticationConverterX509ClientCertificateAuthenticationConverterClientSecretBasicAuthenticationConverterClientSecretPostAuthenticationConverterPublicClientAuthenticationConverter 组成。

  • AuthenticationManager — 一个 AuthenticationManager,由 JwtClientAssertionAuthenticationProviderX509ClientCertificateAuthenticationProviderClientSecretAuthenticationProviderPublicClientAuthenticationProvider 组成。

  • AuthenticationSuccessHandler — 一个内部实现,用于将“已认证的” OAuth2ClientAuthenticationToken(当前 Authentication)关联到 SecurityContext

  • AuthenticationFailureHandler — 一个内部实现,使用与 OAuth2AuthenticationException 关联的 OAuth2Error 返回 OAuth2 错误响应。

定制 Jwt Client Assertion 验证

JwtClientAssertionDecoderFactory.DEFAULT_JWT_VALIDATOR_FACTORY 是默认的工厂,它为指定的 RegisteredClient 提供一个 OAuth2TokenValidator<Jwt>,用于验证 Jwt client assertion 的 isssubaudexpnbf Claims。

JwtClientAssertionDecoderFactory 提供了通过向 setJwtValidatorFactory() 提供类型为 Function<RegisteredClient, OAuth2TokenValidator<Jwt>> 的自定义工厂来覆盖默认 Jwt client assertion 验证的能力。

JwtClientAssertionDecoderFactoryJwtClientAssertionAuthenticationProvider 使用的默认 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_AUTHClientAuthenticationMethod.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();