配置模型

預設配置

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.