在微服务对外暴露 HTTPS 接口时,仅由客户端验证服务端证书并不能阻止非法终端调用。X509 双向认证要求双方都出示证书,服务端通过 trustStore 校验客户端身份。Spring Boot 中可通过 @EnableX509 结合 Spring Security 快速启用该机制,但很多项目卡在证书格式与配置映射上。下面从基础环境准备开始,逐步给出可落地的整合方案。

证书与密钥库准备
双向认证依赖两套密钥库:keyStore 存放服务端自己的私钥和证书,trustStore 存放受信任的客户端 CA 证书。使用 JDK 自带的 keytool 即可生成,不需要第三方工具。常见误区是把客户端证书直接导进服务端 keyStore,这会导致服务端在握手时把客户端证书当成自己的链证书,校验直接失败。
生成服务端证书时,CN 最好写域名或本机 IP,否则浏览器或 HTTP 客户端会报主机名不匹配。客户端证书可由同一 CA 签发,也可独立自签,但必须导入服务端 trustStore。下面命令生成服务端密钥库与自签 CA,再用 CA 签发客户端证书并导出为 p12 供 curl 使用。
# 生成服务端密钥库 keytool -genkeypair -alias server -keyalg RSA -keysize 2048 -validity 365 -keystore server.jks -storepass changeit -dname "CN=localhost,OU=dev,O=test" # 导出服务端证书 keytool -exportcert -alias server -keystore server.jks -storepass changeit -file server.crt # 生成客户端密钥库(p12) keytool -genkeypair -alias client -keyalg RSA -keysize 2048 -validity 365 -keystore client.p12 -storetype PKCS12 -storepass changeit -dname "CN=client,OU=dev,O=test"
上述脚本只是最小示例,生产环境应由内部 CA 统一签发。注意 JKS 与 PKCS12 格式在 Spring 配置中写法不同,Spring Boot 2.x 之后默认支持 PKCS12,推荐服务端也用 p12 以减少转换成本。
Security 配置与 EnableX509 使用
@EnableX509 并非单独生效的注解,它通常出现在资源服务器或 Web Security 配置类上,用于声明 X509 认证过滤器。其核心是把客户端证书里的主体信息映射为 Authentication 对象。若缺失对应的 UserDetailsService 或 AuthenticationManager,容器启动会报缺少 bean。
在配置类中,需要通过 x509() 方法挂载证书处理器,并指定用户检索逻辑。下面的 Java 配置演示了如何读取证书 CN 作为用户名,再赋予固定角色。实际项目可改为查数据库或 LDAP。
@Configuration
@EnableWebSecurity
@EnableX509
public class X509SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.x509()
.subjectPrincipalRegex("CN=(.*?)(?:,|$)")
.userDetailsService(userDetailsService());
}
@Bean
public UserDetailsService userDetailsService() {
return username -> User.withUsername(username)
.password("")
.roles("CLIENT")
.build();
}
}
这段配置里 subjectPrincipalRegex 从证书主题提取 CN 当作账号。如果客户端证书主题格式复杂,正则要相应调整。另外 @EnableX509 在较新 Spring Security 版本中已被更细粒度过滤器替代,但老项目升级时保留该注解仍可兼容,只是 IDE 可能提示过时。
application 配置与联调验证
证书文件准备好后,要在 application.yml 中把路径与密码交给嵌入式 Tomcat。Spring Boot 的 ssl 配置项同时控制服务端身份与可选客户端校验。将 client-auth 设为 need,强制双向认证;设为 want 则兼容单向。
以下是典型配置片段,注意 key-store-type 与 trust-store-type 必须和文件格式一致,否则抛出 KeyStoreException。许多排错耗时都花在类型不匹配上。
server:
port: 8443
ssl:
enabled: true
key-store: classpath:server.p12
key-store-password: changeit
key-store-type: PKCS12
trust-store: classpath:trust.p12
trust-store-password: changeit
trust-store-type: PKCS12
client-auth: need
启动后可用 curl 携带客户端 p12 验证。命令中 cert 与 key 需从 p12 提取为 pem,或直接使用 --cert 指向 p12 并给密码。返回 200 说明链路通;若 400 无证书,则检查 client-auth 与 trustStore 导入。
curl -v --cert client.pem --key client.key https://localhost:8443/api/hello
当联调出现 handshake_failure,优先比对服务端 trustStore 是否含客户端证书公钥,以及时间偏差是否超证书有效期。通过开启 -Djavax.net.debug=ssl 可打印握手细节,定位是哪一步被拒。掌握上述步骤,Spring Boot 整合 EnableX509 的双向认证便能稳定落地。
Spring_BootEnableX509双向认证修改时间:2026-08-19 02:30:34