spring - Spring RestTemplate 交换帖子不适用于 SSL 引发 SunCertPathBuilderException
问题描述
我正在使用 restTemplate 来请求使用 SSL 的帖子。问题是我无法通过 SSL 向服务器发送发布请求。我正在使用自签名证书进行通信。然而,奇怪的是,当我通过 SSL 发送 get 请求时,它工作正常。
我不明白为什么 POST 不像 GET 那样工作。这是我使用 restTemplate 的 GET 和 POST。
public <T> T getByRestTemplate(String url, Object param, boolean isSSL, String token, ParameterizedTypeReference<T> responseType) throws RestClientException {
HttpEntity<Object> requestEntity = makeHttpEntity(param, token);
RestTemplate restTemplate = buildRestTemplate(isSSL);
ResponseEntity<T> responseEntity;
responseEntity = restTemplate.exchange(url, HttpMethod.GET, requestEntity, responseType);
return responseEntity.getBody();
}
public <T> T postByRestTemplate(String url, Object param, boolean isSSL, String token, Class<T> responseType) throws RestClientException {
HttpEntity<Object> requestEntity = makeHttpEntity(param, token);
RestTemplate restTemplate = prepareRestTemplate(isSSL);
ResponseEntity<T> responseEntity;
responseEntity = restTemplate.exchange(url, HttpMethod.POST, requestEntity, responseType);
return responseEntity.getBody();
}
private RestTemplate prepareRestTemplate(boolean isSSL){
int connectTimeOut = (appConfigProperties.getConnectTimeOut()!=0)?appConfigProperties.getConnectTimeOut():5000;
int readTimeOut = (appConfigProperties.getReadTimeOut()!=0)?appConfigProperties.getConnectTimeOut():5000;
RestTemplate restTemplate = buildRestTemplate(isSSL);
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
requestFactory.setConnectTimeout(connectTimeOut);
requestFactory.setReadTimeout(readTimeOut);
restTemplate.setRequestFactory(requestFactory);
return restTemplate;
}
private RestTemplate buildRestTemplate(boolean isSSL) {
RestTemplate restTemplate = null;
if (isSSL) {
try {
restTemplate = restTemplateSSL.restTemplateSSL();
} catch (Exception e) {
e.printStackTrace();
}
} else {
restTemplate = restTemplateBuilder.build();
}
return restTemplate;
}
这是与 SSL 设置相关的代码。
private static TrustManager[] createTrustManagers() {
TrustManager[] trustAllCerts;
trustAllCerts = new TrustManager[]{new X509ExtendedTrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] x509Certificates, String s){
}
@Override
public void checkServerTrusted(X509Certificate[] x509Certificates, String s) {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
@Override
public void checkClientTrusted(X509Certificate[] x509Certificates, String s, Socket socket) {
}
@Override
public void checkServerTrusted(X509Certificate[] x509Certificates, String s, Socket socket) {
}
@Override
public void checkClientTrusted(X509Certificate[] x509Certificates, String s, SSLEngine sslEngine) {
}
@Override
public void checkServerTrusted(X509Certificate[] x509Certificates, String s, SSLEngine sslEngine) {
}
}};
return trustAllCerts;
}
public RestTemplate restTemplateSSL() throws Exception {
SSLContext sslContext = SSLContext.getInstance(SSL_TLS);
sslContext.init(null, createTrustManagers(), new java.security.SecureRandom());
SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext,
NoopHostnameVerifier.INSTANCE);
final Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
.register(SSL_HTTPS, csf)
.build();
final PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(registry);
CloseableHttpClient httpClient = HttpClients.custom()
.setSSLSocketFactory(csf)
.setConnectionManager(cm)
.build();
HttpComponentsClientHttpRequestFactory requestFactory =
new HttpComponentsClientHttpRequestFactory();
requestFactory.setHttpClient(httpClient);
return new RestTemplate(requestFactory);
}
这是我得到的日志。
PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target; nested exception is javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target] with root cause
sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:141) ~[na:1.8.0_192]
at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:126) ~[na:1.8.0_192]
at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:280) ~[na:1.8.0_192]
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:392) ~[na:1.8.0_192]
at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:302) ~[na:1.8.0_192]
at sun.security.validator.Validator.validate(Validator.java:262) ~[na:1.8.0_192]
at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:324) ~[na:1.8.0_192]
at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:229) ~[na:1.8.0_192]
at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:124) ~[na:1.8.0_192]
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1621) ~[na:1.8.0_192]
at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:223) ~[na:1.8.0_192]
at sun.security.ssl.Handshaker.processLoop(Handshaker.java:1037) ~[na:1.8.0_192]
at sun.security.ssl.Handshaker.process_record(Handshaker.java:965) ~[na:1.8.0_192]
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1064) ~[na:1.8.0_192]
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1367) ~[na:1.8.0_192]
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1395) ~[na:1.8.0_192]
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1379) ~[na:1.8.0_192]
at org.apache.http.conn.ssl.SSLConnectionSocketFactory.createLayeredSocket(SSLConnectionSocketFactory.java:436) ~[httpclient-4.5.9.jar:4.5.9]
at org.apache.http.conn.ssl.SSLConnectionSocketFactory.connectSocket(SSLConnectionSocketFactory.java:384) ~[httpclient-4.5.9.jar:4.5.9]
at org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.connect(DefaultHttpClientConnectionOperator.java:142) ~[httpclient-4.5.9.jar:4.5.9]
at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:374) ~[httpclient-4.5.9.jar:4.5.9]
at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:393) ~[httpclient-4.5.9.jar:4.5.9]
at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:236) ~[httpclient-4.5.9.jar:4.5.9]
at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:186) ~[httpclient-4.5.9.jar:4.5.9]
at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:89) ~[httpclient-4.5.9.jar:4.5.9]
at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110) ~[httpclient-4.5.9.jar:4.5.9]
at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:185) ~[httpclient-4.5.9.jar:4.5.9]
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:83) ~[httpclient-4.5.9.jar:4.5.9]
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:56) ~[httpclient-4.5.9.jar:4.5.9]
at org.springframework.http.client.HttpComponentsClientHttpRequest.executeInternal(HttpComponentsClientHttpRequest.java:87) ~[spring-web-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.http.client.AbstractBufferingClientHttpRequest.executeInternal(AbstractBufferingClientHttpRequest.java:48) ~[spring-web-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.http.client.AbstractClientHttpRequest.execute(AbstractClientHttpRequest.java:53) ~[spring-web-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:735) ~[spring-web-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:670) ~[spring-web-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:579) ~[spring-web-5.1.8.RELEASE.jar:5.1.8.RELEASE]
我已经阅读了许多其他帖子和 stackoverflow 问答
使用 Spring RestTemplate 访问 Https Rest Service
如何使用 Spring RestTemplate 禁用 SSL 证书检查?
在 Spring RestTemplate 中禁用 SSL 证书验证
以及更多关于这个问题的信息。但没有一个成功。我不确定我还能如何尝试。
解决方案
毕竟这是一个愚蠢的错误。
在为 POST 请求设置 restClient 时,我犯了覆盖 RequestFactory 的错误,因此删除了之前的 SSL 连接设置。
希望没有人犯这种错误!
推荐阅读
- xcode - 致命错误:找不到“矢量”文件,使用 Xcode 10
- jquery - Bootstrap 面板通过滚动将面板主体尺寸增加到固定长度
- vb.net - HtmlAgilityPack 行的 Xpath 语法
- jvm - win10如何通过netbeans8.2调试openjdk9?
- linux - 树莓派 Autostart.desktop 终端
- symfony - DQL 查询多对多 IN
- security - 如何限制项目管理员仅创建新存储库,azure devops 中的主分支
- c# - 具有相同属性存储库模式的多个实体
- jquery - 类中的文本应检查另一个类中的文本,如果匹配,则更改第一个文本的 css 样式
- python - 如何操作字符串中间的文本?