无需导入证书到JVM密钥库,配置带CA及客户端证书的自定义RestTemplate
在Spring Boot中为RestTemplate添加CA证书(PEM文件)
一、修改现有RestTemplate配置,加载CA证书
你的现有代码仅加载了客户端证书作为信任材料,要添加CA证书,需要将CA证书导入信任库,再结合客户端证书构建SSLContext。具体步骤如下:
1. 先添加依赖(解析PEM证书用)
如果用Maven,添加BouncyCastle依赖来解析PEM格式的CA证书:
<dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcpkix-jdk15on</artifactId> <version>1.70</version> </dependency>
2. 修改RestTemplate Bean代码
import org.bouncycastle.cert.X509CertificateHolder; import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; import org.bouncycastle.openssl.PEMParser; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.ClassPathResource; import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; import org.springframework.web.client.RestTemplate; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManagerFactory; import javax.net.ssl.X509TrustManager; import java.io.InputStreamReader; import java.security.KeyStore; import java.security.cert.X509Certificate; @Configuration public class RestTemplateConfig { @Bean public RestTemplate restTemplate() throws Exception { // 1. 加载客户端证书(原有逻辑,假设是PKCS12格式) String clientCertPath = "classpath:client-cert.p12"; char[] clientCertPassword = "your-client-password".toCharArray(); // 2. 从资源文件夹加载CA PEM证书并解析 ClassPathResource caResource = new ClassPathResource("ca-cert.pem"); PEMParser pemParser = new PEMParser(new InputStreamReader(caResource.getInputStream())); X509CertificateHolder caCertHolder = (X509CertificateHolder) pemParser.readObject(); X509Certificate caCert = new JcaX509CertificateConverter().getCertificate(caCertHolder); pemParser.close(); // 3. 创建包含CA证书的信任库 KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); trustStore.load(null, null); trustStore.setCertificateEntry("custom-ca", caCert); // 4. 初始化信任管理器 TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); trustManagerFactory.init(trustStore); X509TrustManager trustManager = (X509TrustManager) trustManagerFactory.getTrustManagers()[0]; // 5. 加载客户端证书作为密钥材料(双向认证用) KeyStore keyStore = KeyStore.getInstance("PKCS12"); keyStore.load(new ClassPathResource(clientCertPath).getInputStream(), clientCertPassword); KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); keyManagerFactory.init(keyStore, clientCertPassword); // 6. 构建SSLContext,同时配置密钥管理器(客户端证书)和信任管理器(CA证书) SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(keyManagerFactory.getKeyManagers(), new X509TrustManager[]{trustManager}, null); // 7. 组装HttpClient和RestTemplate SSLConnectionSocketFactory sslConFactory = new SSLConnectionSocketFactory(sslContext); CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(sslConFactory).build(); HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(httpClient); return new RestTemplate(requestFactory); } }
这段代码会让RestTemplate同时使用客户端证书做双向认证,并且信任指定CA签发的服务端证书。
二、Spring Boot中的其他实现方式
1. 全局SSL配置(application.properties)
如果希望整个应用都信任该CA证书,可以把CA证书导入到JKS格式的信任库中,然后在application.properties配置全局SSL参数:
# 信任库路径(资源文件夹下的truststore.jks) server.ssl.trust-store=classpath:truststore.jks server.ssl.trust-store-password=your-truststore-password server.ssl.trust-store-type=JKS
注意:这种方式是全局生效的,会影响应用内所有SSL请求,不是仅针对单个RestTemplate。
2. 结合RestTemplateBuilder简化配置
如果需要利用Spring Boot的RestTemplateBuilder做额外配置(比如超时、拦截器),可以这样整合自定义SSL:
@Bean public RestTemplate restTemplate(RestTemplateBuilder builder) throws Exception { // 先按照前面的步骤构建好sslContext SSLConnectionSocketFactory sslConFactory = new SSLConnectionSocketFactory(sslContext); CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(sslConFactory).build(); HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(httpClient); // 用builder整合自定义请求工厂,同时可以添加其他配置 return builder.requestFactory(() -> requestFactory) .setConnectTimeout(Duration.ofSeconds(10)) .build(); }
注意事项
- 如果CA证书是链式结构(包含中间证书),需要把所有层级的证书都加入到信任库中。
- 请根据你的Spring Boot版本选择兼容的BouncyCastle版本,避免依赖冲突。
- 如果客户端证书也是PEM格式,同样可以用BouncyCastle解析后导入到KeyStore中使用。
内容的提问来源于stack exchange,提问作者Victoria Agafonova
相关产品推荐
相关产品推荐

