配置模型

默认配置

OAuth2AuthorizationServerConfiguration 是一个 @Configuration,它为 OAuth2 授权服务器提供了最小的默认配置。

OAuth2AuthorizationServerConfiguration 使用 OAuth2AuthorizationServerConfigurer 来应用默认配置,并注册一个由所有支持 OAuth2 授权服务器的基础设施组件组成的 SecurityFilterChain @Bean

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);
	}

}
授权码授权要求资源所有者进行身份验证。因此,除了默认的 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,这对于 OpenID Connect 1.0 用户信息端点OpenID Connect 1.0 客户端注册端点必需的

以下示例展示了如何注册一个 JwtDecoder @Bean

@Bean
public JwtDecoder jwtDecoder(JWKSource<SecurityContext> jwkSource) {
	return OAuth2AuthorizationServerConfiguration.jwtDecoder(jwkSource);
}

OAuth2AuthorizationServerConfiguration 的主要目的是提供一种方便的方法来为 OAuth2 授权服务器应用最小的默认配置。然而,在大多数情况下,需要自定义配置。

自定义配置

OAuth2AuthorizationServerConfigurer 提供了为 OAuth2 授权服务器完全自定义安全配置的能力。它允许您指定要使用的核心组件——例如,RegisteredClientRepositoryOAuth2AuthorizationServiceOAuth2TokenGenerator 等。此外,它还允许您自定义协议端点的请求处理逻辑——例如,授权端点设备授权端点设备验证端点令牌端点令牌内省端点 等。

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)
				.pushedAuthorizationRequestEndpoint(pushedAuthorizationRequestEndpoint -> { })  (8)
				.deviceAuthorizationEndpoint(deviceAuthorizationEndpoint -> { })	(9)
				.deviceVerificationEndpoint(deviceVerificationEndpoint -> { })	(10)
				.tokenEndpoint(tokenEndpoint -> { })	(11)
				.tokenIntrospectionEndpoint(tokenIntrospectionEndpoint -> { })	(12)
				.tokenRevocationEndpoint(tokenRevocationEndpoint -> { })	(13)
				.authorizationServerMetadataEndpoint(authorizationServerMetadataEndpoint -> { })	(14)
				.oidc(oidc -> oidc
					.providerConfigurationEndpoint(providerConfigurationEndpoint -> { })	(15)
					.logoutEndpoint(logoutEndpoint -> { })	(16)
					.userInfoEndpoint(userInfoEndpoint -> { })	(17)
					.clientRegistrationEndpoint(clientRegistrationEndpoint -> { })	(18)
				)
		);

	return http.build();
}
1 registeredClientRepository():用于管理新旧客户端的 RegisteredClientRepository (必需)。
2 authorizationService():用于管理新旧授权的 OAuth2AuthorizationService
3 authorizationConsentService():用于管理新旧授权同意的 OAuth2AuthorizationConsentService
4 authorizationServerSettings():用于自定义 OAuth2 授权服务器配置设置的 AuthorizationServerSettings (必需)。
5 tokenGenerator():用于生成 OAuth2 授权服务器支持的令牌的 OAuth2TokenGenerator
6 clientAuthentication()OAuth2 客户端身份验证的配置器。
7 authorizationEndpoint()OAuth2 授权端点的配置器。
8 pushedAuthorizationRequestEndpoint()OAuth2 推送授权请求端点的配置器。
9 deviceAuthorizationEndpoint()OAuth2 设备授权端点的配置器。
10 deviceVerificationEndpoint()OAuth2 设备验证端点的配置器。
11 tokenEndpoint()OAuth2 令牌端点的配置器。
12 tokenIntrospectionEndpoint()OAuth2 令牌内省端点的配置器。
13 tokenRevocationEndpoint()OAuth2 令牌撤销端点的配置器。
14 authorizationServerMetadataEndpoint()OAuth2 授权服务器元数据端点的配置器。
15 providerConfigurationEndpoint()OpenID Connect 1.0 提供商配置端点的配置器。
16 logoutEndpoint()OpenID Connect 1.0 登出端点的配置器。
17 userInfoEndpoint()OpenID Connect 1.0 用户信息端点的配置器。
18 clientRegistrationEndpoint()OpenID Connect 1.0 客户端注册端点的配置器。

配置授权服务器设置

AuthorizationServerSettings 包含 OAuth2 授权服务器的配置设置。它指定了协议端点的 URI 以及 颁发者标识符。协议端点的默认 URI 如下:

public final class AuthorizationServerSettings extends AbstractSettings {

	...

	public static Builder builder() {
		return new Builder()
			.authorizationEndpoint("/oauth2/authorize")
			.pushedAuthorizationRequestEndpoint("/oauth2/par")
			.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")
		.pushedAuthorizationRequestEndpoint("/oauth2/v1/par")
		.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 和“当前”颁发者标识符的访问。

如果未在 AuthorizationServerSettings.builder().issuer(String) 中配置颁发者标识符,则会从当前请求中解析。
AuthorizationServerContext 可通过 AuthorizationServerContextHolder 访问,它通过使用 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()AuthenticationSuccessHandler后处理器),用于处理成功的客户端身份验证并将 OAuth2ClientAuthenticationToken 关联到 SecurityContext
6 errorResponseHandler()AuthenticationFailureHandler后处理器),用于处理失败的客户端身份验证并返回 OAuth2Error 响应

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

默认情况下,OAuth2 令牌端点OAuth2 令牌内省端点OAuth2 令牌撤销端点 需要客户端身份验证。支持的客户端身份验证方法有 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 客户端断言验证

JwtClientAssertionDecoderFactory.DEFAULT_JWT_VALIDATOR_FACTORY 是默认的工厂,它为指定的 RegisteredClient 提供一个 OAuth2TokenValidator<Jwt>,用于验证 Jwt 客户端断言的 isssubaudexpnbf 声明。

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

JwtClientAssertionDecoderFactoryJwtClientAssertionAuthenticationProvider 使用的默认 JwtDecoderFactory,它为指定的 RegisteredClient 提供一个 JwtDecoder,用于在 OAuth2 客户端身份验证期间验证 Jwt 持有者令牌。

自定义 JwtClientAssertionDecoderFactory 的常见用例是验证 Jwt 客户端断言中的其他声明。

以下示例展示了如何使用自定义的 JwtClientAssertionDecoderFactory 配置 JwtClientAssertionAuthenticationProvider,该工厂验证 Jwt 客户端断言中的附加声明:

@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);
			}
		});
}

自定义双向 TLS 客户端身份验证

X509ClientCertificateAuthenticationProvider 用于在 OAuth2 客户端身份验证期间使用 ClientAuthenticationMethod.TLS_CLIENT_AUTHClientAuthenticationMethod.SELF_SIGNED_TLS_CLIENT_AUTH 方法时,对接收到的客户端 X509Certificate 链进行身份验证。它还包含一个“证书验证器”,用于在 TLS 握手成功完成后验证客户端 X509Certificate 的内容。

PKI 双向 TLS 方法

对于 PKI 双向 TLS (ClientAuthenticationMethod.TLS_CLIENT_AUTH) 方法,证书验证器的默认实现会根据设置 RegisteredClient.getClientSettings.getX509CertificateSubjectDN() 验证客户端 X509Certificate 的主题可分辨名称。

如果您需要验证客户端 X509Certificate 的另一个属性,例如主题备用名称 (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);
				}
			});
}

自签名证书双向 TLS 方法

对于自签名证书双向 TLS (ClientAuthenticationMethod.SELF_SIGNED_TLS_CLIENT_AUTH) 方法,证书验证器的默认实现将使用设置 RegisteredClient.getClientSettings.getJwkSetUrl() 检索客户端的 JSON Web 密钥集,并期望找到与 TLS 握手期间收到的客户端 X509Certificate 匹配的项。

RegisteredClient.getClientSettings.getJwkSetUrl() 设置用于通过 JSON Web 密钥 (JWK) 集检索客户端的证书。证书由集中单个 JWK 的 x5c 参数表示。

客户端证书绑定访问令牌

当在令牌端点使用双向 TLS 客户端身份验证时,授权服务器能够将颁发的访问令牌绑定到客户端的 X509Certificate。绑定是通过计算客户端 X509Certificate 的 SHA-256 指纹并将该指纹与访问令牌关联来完成的。例如,一个 JWT 访问令牌将包含一个 x5t#S256 声明,其中包含 X509Certificate 指纹,位于顶级 cnf(确认方法)声明中。

将访问令牌绑定到客户端的 X509Certificate 提供了在受保护资源访问期间实现所有权证明机制的能力。例如,受保护资源将获取在双向 TLS 身份验证期间使用的客户端 X509Certificate,然后验证证书指纹是否与与访问令牌关联的 x5t#S256 声明匹配。

以下示例展示了如何为客户端启用证书绑定访问令牌:

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();
© . This site is unofficial and not affiliated with VMware.