SpringBoot3使用RestTemplate请求接口忽略SSL证书
概述
我在项目中使用SpringBoot3版本+中RestTemplate请求接口时候报错:
PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to fin
注意:springBoot3版本+RestTemplate对应的是spring-web-6.+版本旧版本不适用以下解决方案,构建RestTemplateConfigl类可能会找不到对应方法!!!
错误原因
在使用 RestTemplate
调用 HTTPS 接口时,出现 PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
错误,通常是因为 Java 应用程序无法验证服务器的 SSL 证书。
具体原因如下:
-
证书不受信任:Java 的默认信任库(
cacerts
)中没有包含服务器使用的 SSL 证书或中间证书。Java 使用这个信任库来验证服务器的证书链。 -
自签名证书:如果服务器使用的是自签名证书,而不是由受信任的证书颁发机构(CA)签发的证书,Java 默认不会信任这种证书。
-
证书链不完整:服务器的 SSL 证书链不完整,缺少中间证书,导致 Java 无法构建完整的证书路径。
解决方案
1. 将服务器证书添加到 Java 的信任库
如果服务器使用的是自签名证书或不受信任的证书,可以将该证书添加到 Java 的信任库中。
步骤:
-
获取服务器证书:
-
使用浏览器访问目标 HTTPS 接口,导出服务器的 SSL 证书。
-
或者使用
openssl
命令获取证书:
-
openssl s_client -connect <服务器地址>:443 -showcerts
-
-
将输出中的证书部分保存为
.crt
文件。
-
-
将证书导入 Java 信任库:
-
找到 Java 的
cacerts
文件,通常位于$JAVA_HOME/lib/security/cacerts
。 -
使用
keytool
将证书导入信任库:
-
keytool -import -trustcacerts -file <证书文件> -keystore $JAVA_HOME/lib/security/cacerts -alias <别名>
-
-
默认密码是
changeit
。
-
-
重启应用程序:确保应用程序重新加载信任库。
2. 忽略 SSL 证书验证(不推荐)
如果你在开发环境中,且不关心证书验证,可以临时忽略 SSL 证书验证。注意:这种方法不安全,不推荐在生产环境中使用。
步骤:
-
自定义
RestTemplate
:-
创建一个自定义的
SSLContext
,忽略证书验证。 -
使用
NoopHostnameVerifier
忽略主机名验证。
-
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder;
import org.apache.hc.client5.http.ssl.NoopHostnameVerifier;
import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactoryBuilder;
import org.apache.hc.client5.http.ssl.TrustAllStrategy;
import org.apache.hc.core5.ssl.SSLContextBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate(ClientHttpRequestFactory factory) {
return new RestTemplate(factory);
}
@Bean
public ClientHttpRequestFactory simpleClientHttpRequestFactory() throws Exception {
HttpComponentsClientHttpRequestFactory factory = generateHttpRequestFactory();
factory.setConnectTimeout(15000);
factory.setConnectionRequestTimeout(5000);
return factory;
}
/**
* 构造跳过SSL ClientHttp工厂
*
* @return
* @throws NoSuchAlgorithmException
* @throws KeyManagementException
* @throws KeyStoreException
*/
public static HttpComponentsClientHttpRequestFactory generateHttpRequestFactory()
throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException {
CloseableHttpClient httpclient = HttpClients.custom()
.setConnectionManager(PoolingHttpClientConnectionManagerBuilder.create()
.setSSLSocketFactory(SSLConnectionSocketFactoryBuilder.create()
.setSslContext(SSLContextBuilder.create()
.loadTrustMaterial(TrustAllStrategy.INSTANCE)
.build())
.setHostnameVerifier(NoopHostnameVerifier.INSTANCE)
.build())
.build())
.build();
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
factory.setHttpClient(httpclient);
return factory;
}
}
-
使用自定义的
RestTemplate
:-
在调用 HTTPS 接口时,使用上述方法创建的
RestTemplate
。
-
3. 使用受信任的证书
如果可能,建议使用由受信任的 CA 签发的证书,而不是自签名证书。这样可以避免证书验证问题。
总结
-
推荐方案:将服务器证书添加到 Java 的信任库中,确保证书链完整且受信任。
-
临时方案:在开发环境中,可以临时忽略 SSL 证书验证,但不建议在生产环境中使用。
-
最佳实践:使用受信任的 CA 签发的证书,确保 SSL/TLS 通信的安全性。