对于最新的稳定版本,请使用 Spring Authorization Server 1.5.2spring-doc.cadn.net.cn

配置模型

默认配置

OAuth2AuthorizationServerConfiguration是一个@Configuration为 OAuth2 授权服务器提供最小的默认配置。spring-doc.cadn.net.cn

OAuth2AuthorizationServerConfiguration使用OAuth2AuthorizationServerConfigurer应用默认配置并注册一个SecurityFilterChain @Bean由支持 OAuth2 授权服务器的所有基础设施组件组成。spring-doc.cadn.net.cn

OAuth2 授权服务器SecurityFilterChain @Bean配置了以下默认协议端点:spring-doc.cadn.net.cn

JWKSource<SecurityContext> @Bean已注册。

以下示例演示如何使用OAuth2AuthorizationServerConfiguration要应用最小默认配置,请执行以下作:spring-doc.cadn.net.cn

@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:spring-doc.cadn.net.cn

@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 协议端点:spring-doc.cadn.net.cn

默认情况下,OpenID Connect 1.0 客户端注册端点处于禁用状态,因为许多部署不需要动态客户端注册。
OAuth2AuthorizationServerConfiguration.jwtDecoder(JWKSource<SecurityContext>)是一种便利(static) 实用程序方法,可用于注册JwtDecoder @Bean,这是 OpenID Connect 1.0 UserInfo 端点OpenID Connect 1.0 客户端注册端点必需的。

以下示例演示如何注册JwtDecoder @Bean:spring-doc.cadn.net.cn

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

的主要意图OAuth2AuthorizationServerConfiguration是提供一种方便的方法来为 OAuth2 授权服务器应用最小默认配置。但是,在大多数情况下,需要自定义配置。spring-doc.cadn.net.cn

自定义配置

OAuth2AuthorizationServerConfigurer提供了完全自定义 OAuth2 授权服务器安全配置的功能。 它允许您指定要使用的核心组件 - 例如RegisteredClientRepository,OAuth2AuthorizationService,OAuth2TokenGenerator,等。 此外,它还允许您自定义协议端点的请求处理逻辑,例如,授权端点设备授权端点设备验证端点Tokens端点Tokens自检端点等。spring-doc.cadn.net.cn

OAuth2AuthorizationServerConfigurer提供以下配置选项:spring-doc.cadn.net.cn

@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():这AuthorizationServerSettings (必填)用于自定义 OAuth2 授权服务器的配置设置。
5 tokenGenerator():这OAuth2TokenGenerator用于生成 OAuth2 授权服务器支持的Tokens。
6 clientAuthentication()OAuth2 客户端身份验证的配置器。
7 authorizationEndpoint()OAuth2 授权端点的配置器。
8 deviceAuthorizationEndpoint()OAuth2 设备授权端点的配置器。
9 deviceVerificationEndpoint()OAuth2 设备验证端点的配置程序。
10 tokenEndpoint()OAuth2 Tokens端点的配置器。
11 tokenIntrospectionEndpoint()OAuth2 Tokens自检端点的配置器。
12 tokenRevocationEndpoint()OAuth2 Tokens吊销端点的配置器。
13 authorizationServerMetadataEndpoint()OAuth2 授权服务器元数据端点的配置器。
14 providerConfigurationEndpoint()OpenID Connect 1.0 提供程序配置端点的配置器。
15 logoutEndpoint()OpenID Connect 1.0 注销端点的配置器。
16 userInfoEndpoint()OpenID Connect 1.0 UserInfo 端点的配置器。
17 clientRegistrationEndpoint()OpenID Connect 1.0 客户端注册端点的配置器。

配置授权服务器设置

AuthorizationServerSettings包含 OAuth2 授权服务器的配置设置。 它指定了URI用于协议端点以及颁发者标识符。 默认值URI对于协议端点,如下所示:spring-doc.cadn.net.cn

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:spring-doc.cadn.net.cn

@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以及“当前”发行人标识符。spring-doc.cadn.net.cn

如果颁发者标识符未在AuthorizationServerSettings.builder().issuer(String),则从当前请求中解析。
AuthorizationServerContext可通过AuthorizationServerContextHolder,它通过使用ThreadLocal.

配置客户端身份验证

OAuth2ClientAuthenticationConfigurer提供自定义 OAuth2 客户端身份验证的功能。 它定义了扩展点,允许您自定义客户端身份验证请求的预处理、主处理和后处理逻辑。spring-doc.cadn.net.cn

OAuth2ClientAuthenticationConfigurer提供以下配置选项:spring-doc.cadn.net.cn

@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提供对List默认和(可选)添加AuthenticationConverter允许添加、删除或自定义特定的AuthenticationConverter.
3 authenticationProvider():添加一个AuthenticationProvider (主处理器)用于验证OAuth2ClientAuthenticationToken.
4 authenticationProviders():将Consumer提供对List默认和(可选)添加AuthenticationProvider允许添加、删除或自定义特定的AuthenticationProvider.
5 authenticationSuccessHandler():这AuthenticationSuccessHandler (后处理器)用于处理成功的客户端身份验证并关联OAuth2ClientAuthenticationTokenSecurityContext.
6 errorResponseHandler():这AuthenticationFailureHandler (后处理器)用于处理失败的客户端身份验证并返回OAuth2Error响应.

OAuth2ClientAuthenticationConfigurer配置OAuth2ClientAuthenticationFilter并将其注册到 OAuth2 授权服务器SecurityFilterChain @Bean.OAuth2ClientAuthenticationFilterFilter处理客户端身份验证请求。spring-doc.cadn.net.cn

默认情况下,OAuth2 Tokens端点OAuth2 Tokens检测端点OAuth2 Tokens吊销端点需要客户端身份验证。 支持的客户端身份验证方法包括client_secret_basic,client_secret_post,private_key_jwt,client_secret_jwt,tls_client_auth,self_signed_tls_client_authnone(公共客户端)。spring-doc.cadn.net.cn

OAuth2ClientAuthenticationFilter配置为以下默认值:spring-doc.cadn.net.cn

  • AuthenticationConverter— 一个DelegatingAuthenticationConverterJwtClientAssertionAuthenticationConverter,X509ClientCertificateAuthenticationConverter,ClientSecretBasicAuthenticationConverter,ClientSecretPostAuthenticationConverterPublicClientAuthenticationConverter.spring-doc.cadn.net.cn

  • AuthenticationManager— 一个AuthenticationManagerJwtClientAssertionAuthenticationProvider,X509ClientCertificateAuthenticationProvider,ClientSecretAuthenticationProviderPublicClientAuthenticationProvider.spring-doc.cadn.net.cn

  • AuthenticationSuccessHandler— 将“已验证”关联的内部实现OAuth2ClientAuthenticationToken(当前Authentication) 设置为SecurityContext.spring-doc.cadn.net.cn

  • AuthenticationFailureHandler— 使用OAuth2ErrorOAuth2AuthenticationException返回 OAuth2 错误响应。spring-doc.cadn.net.cn

自定义 Jwt 客户端断言验证

JwtClientAssertionDecoderFactory.DEFAULT_JWT_VALIDATOR_FACTORY是默认工厂,它提供了OAuth2TokenValidator<Jwt>对于指定的RegisteredClient并用于验证iss,sub,aud,expnbf的声明Jwt客户端断言。spring-doc.cadn.net.cn

JwtClientAssertionDecoderFactory提供覆盖默认值Jwt通过提供类型Function<RegisteredClient, OAuth2TokenValidator<Jwt>>setJwtValidatorFactory().spring-doc.cadn.net.cn

JwtClientAssertionDecoderFactory是默认值JwtDecoderFactory使用者JwtClientAssertionAuthenticationProvider这提供了一个JwtDecoder对于指定的RegisteredClient并用于验证JwtOAuth2 客户端身份验证期间的持有者Tokens。

自定义的常见用例JwtClientAssertionDecoderFactory是为了验证Jwt客户端断言。spring-doc.cadn.net.cn

以下示例演示如何配置JwtClientAssertionAuthenticationProvider与定制的JwtClientAssertionDecoderFactory验证Jwt客户端断言:spring-doc.cadn.net.cn

@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用于对客户端进行身份验证X509Certificate链收到时ClientAuthenticationMethod.TLS_CLIENT_AUTHClientAuthenticationMethod.SELF_SIGNED_TLS_CLIENT_AUTH方法在 OAuth2 客户端身份验证期间使用。它还由一个“证书验证器”组成,用于验证客户端的内容X509CertificateTLS 握手成功完成后。spring-doc.cadn.net.cn

PKI 互 TLS 方法

对于 PKI 互 TLS (ClientAuthenticationMethod.TLS_CLIENT_AUTH) 方法,证书验证程序的默认实现验证客户端的主题可分辨名X509Certificate反对设定RegisteredClient.getClientSettings.getX509CertificateSubjectDN().spring-doc.cadn.net.cn

如果需要验证客户端的其他属性X509Certificate,例如,使用者备用名称 (SAN) 条目,以下示例显示如何配置X509ClientCertificateAuthenticationProvider使用证书验证程序的自定义实现:spring-doc.cadn.net.cn

@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()并期望找到与客户匹配的X509Certificate在 TLS 握手期间收到。spring-doc.cadn.net.cn

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

客户端证书绑定访问Tokens

在Tokens端点使用互 TLS 客户端身份验证时,授权服务器能够将颁发的访问Tokens绑定到客户端的X509Certificate. 绑定是通过计算客户端的X509Certificate并将指纹与访问Tokens相关联。 例如,JWT 访问Tokens将包含一个x5t#S256声明,其中包含X509Certificate指纹,在顶级cnf(确认方法)索赔。spring-doc.cadn.net.cn

将访问Tokens绑定到客户端的X509Certificate提供了在受保护的资源访问期间实现所有权证明机制的能力。 例如,受保护的资源将获取客户端的X509Certificate在相互 TLS 身份验证期间使用,然后验证证书指纹是否与x5t#S256与访问Tokens关联的声明。spring-doc.cadn.net.cn

以下示例演示如何为客户端启用证书绑定访问Tokens:spring-doc.cadn.net.cn

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