Java6中调用REST Web服务遇证书路径错误的解决方案咨询
解决Rest调用SSL证书信任问题(unable to find valid certification path to requested target)
问题原因
目标服务器使用的SSL证书未被JVM默认信任库(cacerts)收录,常见于自签名证书、私有CA签发的证书场景。
解决方案
方案一:将证书导入JVM全局信任库(生产环境推荐)
这种方式让整个JVM信任该证书,所有应用都能受益:
- 导出目标证书
- 浏览器方式:访问目标URL,点击地址栏锁图标 → 证书 → 详细信息 → 复制到文件,选择DER格式保存为
server.crt。 - 命令行方式(需安装openssl):
openssl s_client -connect 197.5.145.85:13002 < /dev/null | openssl x509 -outform PEM > server.crt
- 浏览器方式:访问目标URL,点击地址栏锁图标 → 证书 → 详细信息 → 复制到文件,选择DER格式保存为
- 导入到JVM信任库
找到JRE安装目录下的lib/security/cacerts文件,默认密码为changeit,执行以下命令:
按提示输入密码,确认导入即可。keytool -import -alias sms-server-cert -file server.crt -keystore $JAVA_HOME/jre/lib/security/cacerts
方案二:自定义RestTemplate跳过SSL验证(仅测试环境使用)
生产环境禁止使用,此方法会完全忽略证书和主机名验证,存在严重安全风险:
import org.springframework.http.client.SimpleClientHttpRequestFactory; import org.springframework.web.client.RestTemplate; import org.springframework.http.HttpHeaders; import org.springframework.http.ResponseEntity; import javax.net.ssl.*; import java.security.cert.X509Certificate; public void postFromURL(String url) { RestTemplate restTemplate = new RestTemplate(createIgnoringSslFactory()); HttpHeaders headers = new HttpHeaders(); headers.set("Authorization", "Bearer "); ResponseEntity<Object> response = restTemplate.postForEntity(url, null, Object.class); } private SimpleClientHttpRequestFactory createIgnoringSslFactory() { SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory(); try { // 构建信任所有证书的SSL上下文 SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(null, new TrustManager[]{new X509TrustManager() { @Override public void checkClientTrusted(X509Certificate[] chain, String authType) {} @Override public void checkServerTrusted(X509Certificate[] chain, String authType) {} @Override public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; } }}, new java.security.SecureRandom()); factory.setSslContext(sslContext); // 禁用主机名验证 factory.setHostnameVerifier((hostname, session) -> true); } catch (Exception e) { throw new RuntimeException("初始化SSL上下文失败", e); } return factory; }
方案三:自定义RestTemplate信任指定证书(生产环境可选)
仅让当前RestTemplate信任目标证书,不修改全局JVM设置:
- 将导出的
server.crt放在项目资源目录(如src/main/resources/certs/) - 编写代码加载证书:
import org.springframework.http.client.SimpleClientHttpRequestFactory; import org.springframework.web.client.RestTemplate; import org.springframework.http.HttpHeaders; import org.springframework.http.ResponseEntity; import org.springframework.util.ResourceUtils; import javax.net.ssl.*; import java.io.FileInputStream; import java.security.KeyStore; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; public void postFromURL(String url) { RestTemplate restTemplate = new RestTemplate(createCustomSslFactory()); HttpHeaders headers = new HttpHeaders(); headers.set("Authorization", "Bearer "); ResponseEntity<Object> response = restTemplate.postForEntity(url, null, Object.class); } private SimpleClientHttpRequestFactory createCustomSslFactory() { SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory(); try { // 加载证书文件 CertificateFactory certFactory = CertificateFactory.getInstance("X.509"); X509Certificate serverCert = (X509Certificate) certFactory.generateCertificate( new FileInputStream(ResourceUtils.getFile("classpath:certs/server.crt"))); // 创建自定义信任库 KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); trustStore.load(null, null); trustStore.setCertificateEntry("sms-server-cert", serverCert); // 初始化TrustManagerFactory TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); tmf.init(trustStore); // 构建SSL上下文 SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(null, tmf.getTrustManagers(), new java.security.SecureRandom()); factory.setSslContext(sslContext); } catch (Exception e) { throw new RuntimeException("初始化自定义SSL上下文失败", e); } return factory; }
内容的提问来源于stack exchange,提问作者darine
相关产品推荐
相关产品推荐

