X.509 认证
X.509 证书认证最常见的用途是在使用 SSL 时验证服务器的身份,最常见的情况是浏览器通过 HTTPS 访问网站时。 浏览器会自动检查服务器提供的证书是否由其内置的受信任证书颁发机构列表中的某一个机构签发(数字签名)。
你也可以在SSL中使用“双向认证”(mutual authentication)。在这种情况下,服务器会在SSL握手过程中向客户端请求一个有效的证书。 服务器通过验证客户端证书是否由受信任的权威机构签发来对客户端进行身份认证。 如果客户端提供了有效的证书,应用程序可以通过Servlet API获取该证书。 例如,如果你使用的是Tomcat,应阅读Tomcat SSL配置说明。 在尝试将其与Spring Security集成之前,请先确保上述配置能够正常工作。
Spring Security X.509 模块通过过滤器提取证书。
它将证书映射到应用程序用户,并加载该用户的已授权权限集,以便与标准的 Spring Security 基础设施一起使用,特别是当使用 HttpSecurity DSL时,至少包含 FACTOR_X509 权限。
为您的 Web 应用程序添加 X.509 身份验证
与响应式 X.509 认证类似,Servlet X.509 认证过滤器允许从客户端提供的证书中提取认证Tokens。
以下示例展示了一个响应式的 x509 安全配置:
-
Java
-
Kotlin
-
Xml
@Bean
DefaultSecurityFilterChain springSecurity(HttpSecurity http) throws Exception {
http
.x509(Customizer.withDefaults())
.authorizeHttpRequests((exchanges) -> exchanges
.anyRequest().authenticated()
);
return http.build();
}
@Bean
fun springSecurity(http: HttpSecurity): DefaultSecurityFilterChain? {
http {
authorizeHttpRequests {
authorize(anyRequest, authenticated)
}
x509 { }
}
return http.build()
}
<http>
<intercept-url pattern="/**" access="authenticated"/>
<x509 />
</http>
在上述配置中,当未提供 principalExtractor 或 authenticationManager 时,将使用默认值。
默认的主体提取器是 SubjectX500PrincipalExtractor,它从客户端提供的证书中提取 CN(通用名称)字段。
默认的身份验证管理器是 ReactivePreAuthenticatedAuthenticationManager,它执行用户账户验证,检查是否存在由 principalExtractor 提取的用户名对应的账户,并且该账户未被锁定、禁用或过期。
以下示例演示了如何覆盖这些默认值:
-
Java
-
Kotlin
-
Xml
@Bean
DefaultSecurityFilterChain springSecurity(HttpSecurity http) throws Exception {
SubjectX500PrincipalExtractor principalExtractor = new SubjectX500PrincipalExtractor();
principalExtractor.setExtractPrincipalNameFromEmail(true);
http
.x509((x509) -> x509
.x509PrincipalExtractor(principalExtractor)
)
.authorizeHttpRequests((exchanges) -> exchanges
.anyRequest().authenticated()
);
return http.build();
}
@Bean
fun springSecurity(http: HttpSecurity): DefaultSecurityFilterChain? {
val principalExtractor = SubjectX500PrincipalExtractor()
principalExtractor.setExtractPrincipalNameFromEmail(true)
http {
authorizeHttpRequests {
authorize(anyRequest, authenticated)
}
x509 {
x509PrincipalExtractor = principalExtractor
}
}
return http.build()
}
<http>
<intercept-url pattern="/**" access="authenticated"/>
<x509 principal-extractor-ref="principalExtractor"/>
</http>
<b:bean id="principalExtractor"
class="org.springframework.security.web.authentication.preauth.x509.SubjectX500PrincipalExtractor"
p:extractPrincipalNameFromEmail="true"/>
在上一个示例中,用户名是从客户端证书的 emailAddress 字段中提取的,而不是从 CN(通用名称)中提取,并且账户查找使用了一个自定义的 ReactiveAuthenticationManager 实例。
有关如何配置 Netty 以及 WebClient 或 curl 命令行工具以使用双向 TLS 并启用 X.509 认证的示例,请参见 github.com/spring-projects/spring-security-samples/tree/main/servlet/java-configuration/authentication/x509。
在 Tomcat 中配置 SSL
Spring Security 示例仓库中提供了一些预生成的证书。
如果你不想自己生成证书,可以使用这些证书来启用 SSL 进行测试。
server.jks 文件包含服务器证书、私钥以及颁发机构证书。
此外,还有一些用于示例应用程序中用户的客户端证书文件。
你可以将这些证书安装到浏览器中,以启用 SSL 客户端认证。
要让 Tomcat 支持 SSL,将 server.jks 文件放入 Tomcat 的 conf 目录中,并在 server.xml 文件中添加以下连接器:
<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true" scheme="https" secure="true"
clientAuth="true" sslProtocol="TLS"
keystoreFile="${catalina.home}/conf/server.jks"
keystoreType="JKS" keystorePass="password"
truststoreFile="${catalina.home}/conf/server.jks"
truststoreType="JKS" truststorePass="password"
/>
如果即使客户端未提供证书,您仍希望 SSL 连接能够成功,也可以将 clientAuth 设置为 want。
未提供证书的客户端将无法访问任何由 Spring Security 保护的对象,除非您使用了非 X.509 的身份验证机制,例如表单身份验证。