Configuration Model

Default configuration

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

OAuth2AuthorizationServerConfiguration 使用 OAuth2AuthorizationServerConfigurer 来应用默认配置,并注册一个 SecurityFilterChain @Bean,其中包括支持一个 OAuth2 授权服务器的所有基础架构组件。

OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(HttpSecurity) 是一个便捷 (static) 实用方法,用于将默认 OAuth2 安全配置应用于 HttpSecurity

OAuth2 授权服务器 SecurityFilterChain @Bean 使用以下默认协议端点配置:

如果一个 JWKSource<SecurityContext> @Bean 已注册,则 JWK 集端点 only 已配置。

以下示例演示如何使用 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 grant 要求资源所有者已通过身份验证。因此,除了默认的 OAuth2 安全配置之外,还需要配置一个用户身份验证机制 must

在默认配置中禁用了 OpenID Connect 1.0。以下示例展示了如何通过初始化`OidcConfigurer`来启用OpenID Connect 1.0:

@Bean
public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
	OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);

	http.getConfigurer(OAuth2AuthorizationServerConfigurer.class)
		.oidc(Customizer.withDefaults());	// Initialize `OidcConfigurer`

	return http.build();
}

除了默认协议端点外,OAuth2 授权服务器 SecurityFilterChain @Bean 还使用以下 OpenID Connect 1.0 协议端点配置:

默认情况下,OpenID Connect 1.0 Client Registration endpoint 被禁用,因为许多部署不需要动态客户端注册。

OAuth2AuthorizationServerConfiguration.jwtDecoder(JWKSource<SecurityContext>)`是一个便利(`static)工具方法,可用于注册一个`JwtDecoder``@Bean`,也就是*REQUIRED*的OpenID Connect 1.0 UserInfo endpointOpenID Connect 1.0 Client Registration endpoint

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

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

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

Customizing the configuration

OAuth2AuthorizationServerConfigurer 提供完全自定义针对 OAuth2 授权服务器的安全配置的能力。它允许你指定要使用的核心组件——例如 RegisteredClientRepositoryOAuth2AuthorizationServiceOAuth2TokenGenerator等等。此外,它允许你自定义针对协议端点的请求处理逻辑——例如 authorization endpointdevice authorization endpointdevice verification endpointtoken endpointtoken introspection endpoint等等。

OAuth2AuthorizationServerConfigurer 提供以下配置选项:

@Bean
public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
	OAuth2AuthorizationServerConfigurer authorizationServerConfigurer =
		new OAuth2AuthorizationServerConfigurer();
	http.apply(authorizationServerConfigurer);

	authorizationServerConfigurer
		.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 (REQUIRED)。
2 authorizationService():管理新旧授权的 OAuth2AuthorizationService
3 authorizationConsentService():管理新旧授权同意的 OAuth2AuthorizationConsentService
4 authorizationServerSettings():用于自定义 OAuth2 授权服务器的配置设置的 AuthorizationServerSettings (REQUIRED)。
5 tokenGenerator():用于生成由 OAuth2 授权服务器支持的令牌的 OAuth2TokenGenerator
6 clientAuthentication()OAuth2 Client Authentication 的配置器。
7 authorizationEndpoint()OAuth2 Authorization endpoint 的配置器。
8 deviceAuthorizationEndpoint()OAuth2 Device Authorization endpoint 的配置器。
9 deviceVerificationEndpoint()OAuth2 Device Verification endpoint 的配置器。
10 tokenEndpoint()OAuth2 Token endpoint 的配置器。
11 tokenIntrospectionEndpoint()OAuth2 Token Introspection endpoint 的配置器。
12 tokenRevocationEndpoint()OAuth2 Token Revocation endpoint 的配置器。
13 authorizationServerMetadataEndpoint()OAuth2 Authorization Server Metadata endpoint 的配置器。
14 providerConfigurationEndpoint()OpenID Connect 1.0 Provider Configuration endpoint 的配置器。
15 logoutEndpoint()OpenID Connect 1.0 Logout endpoint 的配置器。
16 userInfoEndpoint()OpenID Connect 1.0 UserInfo endpoint 的配置器。
17 clientRegistrationEndpoint()OpenID Connect 1.0 Client Registration endpoint 的配置器。

Configuring Authorization Server Settings

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 是一个 REQUIRED 组件。

如果尚未提供,@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 和“当前”颁发者标识符。

如果没有在 AuthorizationServerSettings.builder().issuer(String) 中配置发行者标识符,它将从当前请求中解析。

AuthorizationServerContext 可通过 AuthorizationServerContextHolder 访问,它将 AuthorizationServerContext 与当前请求线程关联,方式是使用 ThreadLocal

Configuring Client Authentication

`OAuth2ClientAuthenticationConfigurer`提供了自定义 OAuth2 client authentication的能力。它定义了让你能够自定义针对客户端认证请求进行预处理、主处理和后处理逻辑的扩展点。

OAuth2ClientAuthenticationConfigurer 提供以下配置选项:

@Bean
public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
	OAuth2AuthorizationServerConfigurer authorizationServerConfigurer =
		new OAuth2AuthorizationServerConfigurer();
	http.apply(authorizationServerConfigurer);

	authorizationServerConfigurer
		.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(): 向 OAuth2ClientAuthenticationToken 的实例添加在尝试从 HttpServletRequest 提取客户端凭据时使用的 AuthenticationConverter (pre-processor)。
2 authenticationConverters(): 设置的 Consumer 提供对默认和(可选)添加的 AuthenticationConverter&#8217;s allowing the ability to add, remove, or customize a specific `AuthenticationConverter 的访问权限。
3 authenticationProvider(): 添加用于对 OAuth2ClientAuthenticationToken 进行身份验证的 AuthenticationProvider (main processor)。
4 authenticationProviders():设置一个 Consumer,提供对默认和(可选)添加的 AuthenticationProvider&#8217;s allowing the ability to add, remove, or customize a specific `AuthenticationProviderList 的访问。
5 authenticationSuccessHandler():用于处理成功的客户端身份验证并将 OAuth2ClientAuthenticationTokenSecurityContext 相关联的 AuthenticationSuccessHandler (post-processor)。
6 errorResponseHandler():用于处理失败的客户端身份验证并返回 link:https://datatracker.ietf.org/doc/html/rfc6749#section-5.2[OAuth2Error 响应的 AuthenticationFailureHandler (post-processor)。

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

在默认情况下,客户端验证对于 OAuth2 Token endpointOAuth2 Token Introspection endpointOAuth2 Token Revocation endpoint 是必需的。所支持的客户端验证方法是 client_secret_basicclient_secret_postprivate_key_jwtclient_secret_jwt`和 `none (公共客户端)。

OAuth2ClientAuthenticationFilter 使用以下默认值配置:

  • AuthenticationConverter — 由 JwtClientAssertionAuthenticationConverterClientSecretBasicAuthenticationConverterClientSecretPostAuthenticationConverterPublicClientAuthenticationConverter 组成的一个 DelegatingAuthenticationConverter

  • AuthenticationManager — 由 JwtClientAssertionAuthenticationProviderClientSecretAuthenticationProviderPublicClientAuthenticationProvider 组成的一个 AuthenticationManager

  • AuthenticationSuccessHandler — 将 “authenticated” OAuth2ClientAuthenticationToken (当前 Authentication) 与 SecurityContext 关联的内部实现。

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

Customizing Jwt Client Assertion Validation

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

JwtClientAssertionDecoderFactory 提供了覆盖默认 Jwt 客户端声明验证的功能,方法是向 setJwtValidatorFactory() 提供一个类型为 Function<RegisteredClient, OAuth2TokenValidator<Jwt>> 的自定义工厂。

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

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

以下示例展示了如何使用一个自定义的 JwtClientAssertionDecoderFactory 来配置 JwtClientAssertionAuthenticationProvider,该工厂会在 Jwt 客户端声明中验证其他声明:

@Bean
public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
	OAuth2AuthorizationServerConfigurer authorizationServerConfigurer =
		new OAuth2AuthorizationServerConfigurer();
	http.apply(authorizationServerConfigurer);

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