Reactive X.509 Authentication

Servlet X.509 authentication类似,响应式 x509 认证过滤器允许从客户端提供的证书中提取认证令牌。

Similar to Servlet X.509 authentication, the reactive x509 authentication filter allows extracting an authentication token from a certificate provided by a client.

下面的示例展示了一个响应式 x509 安全配置:

The following example shows a reactive x509 security configuration:

  • Java

  • Kotlin

@Bean
public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
	http
		.x509(withDefaults())
		.authorizeExchange(exchanges -> exchanges
		    .anyExchange().permitAll()
		);
	return http.build();
}
@Bean
fun securityWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
    return http {
        x509 { }
        authorizeExchange {
            authorize(anyExchange, authenticated)
        }
    }
}

在前面的配置中,当既未提供 principalExtractor 也未提供 authenticationManager 时,将使用默认设置。默认 principal 提取器为 SubjectDnX509PrincipalExtractor,它从客户端提供的证书中提取 CN(通用名称)字段。默认认证管理器为 ReactivePreAuthenticatedAuthenticationManager,它执行用户帐户验证,即检查是否存在由 principalExtractor 提取的名称且未锁定、未禁用或未过期。

In the preceding configuration, when neither principalExtractor nor authenticationManager is provided, defaults are used. The default principal extractor is SubjectDnX509PrincipalExtractor, which extracts the CN (common name) field from a certificate provided by a client. The default authentication manager is ReactivePreAuthenticatedAuthenticationManager, which performs user account validation, checking that a user account with a name extracted by principalExtractor exists and that it is not locked, disabled, or expired.

下面的示例演示了如何重写这些默认值:

The following example demonstrates how these defaults can be overridden:

  • Java

  • Kotlin

@Bean
public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
	SubjectDnX509PrincipalExtractor principalExtractor =
	        new SubjectDnX509PrincipalExtractor();

	principalExtractor.setSubjectDnRegex("OU=(.*?)(?:,|$)");

	ReactiveAuthenticationManager authenticationManager = authentication -> {
		authentication.setAuthenticated("Trusted Org Unit".equals(authentication.getName()));
		return Mono.just(authentication);
	};

	http
		.x509(x509 -> x509
		    .principalExtractor(principalExtractor)
		    .authenticationManager(authenticationManager)
		)
		.authorizeExchange(exchanges -> exchanges
		    .anyExchange().authenticated()
		);
	return http.build();
}
@Bean
fun securityWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain? {
    val customPrincipalExtractor = SubjectDnX509PrincipalExtractor()
    customPrincipalExtractor.setSubjectDnRegex("OU=(.*?)(?:,|$)")
    val customAuthenticationManager = ReactiveAuthenticationManager { authentication: Authentication ->
        authentication.isAuthenticated = "Trusted Org Unit" == authentication.name
        Mono.just(authentication)
    }
    return http {
        x509 {
            principalExtractor = customPrincipalExtractor
            authenticationManager = customAuthenticationManager
        }
        authorizeExchange {
            authorize(anyExchange, authenticated)
        }
    }
}

在上个示例中,用户名是从客户端证书的 OU 字段中提取的,而不是 CN,并且根本不使用 ReactiveUserDetailsService 执行帐户查找。而如果提供给名为 “Trusted Org Unit” 的 OU 的证书,则对此请求进行认证。

In the previous example, a username is extracted from the OU field of a client certificate instead of CN, and account lookup using ReactiveUserDetailsService is not performed at all. Instead, if the provided certificate issued to an OU named “Trusted Org Unit”, a request is authenticated.

关于如何配置Netty和`WebClient`或`curl`命令行工具以使用双向TLS并启用X.509身份验证,请参阅[role="bare"][role="bare"]https://github.com/spring-projects/spring-security-samples/tree/main/servlet/java-configuration/authentication/x509。

For an example of configuring Netty and WebClient or curl command-line tool to use mutual TLS and enable X.509 authentication, see [role="bare"]https://github.com/spring-projects/spring-security-samples/tree/main/servlet/java-configuration/authentication/x509.