一、前言
最近在对接腾讯会议API接口,在鉴权完成后开始调用对方的接口,在此过程中出现调用报错:javax.net.ssl.SSLHandshakeException。
二、出现原因
当你在进行https请求时,JDK中不存在三方服务的信任证书,导致出现错误javax.net.ssl.SSLHandshakeException:sun.security.validator.ValidatorException:PKIX路径构建失败。
三、解决方法
1、获取根证书安装证书到你的JRE的Java cacerts中(安装证书到PATHTOYOURJDK/JRE/lib目录/ cacerts中)。
2、忽略SSL证书的校验。
这里因为很多情况没有证书,所以采用第二种方案,在你的代码中进行忽略SSL证书校验。
四、代码
这里要区分你使用的是那种方式调用三方服务(RestTemplate 、OkHttpClient)。
1、RestTemplate
package com.hikvision.meeting.config;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
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.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
import javax.net.ssl.*;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
/**
* @author dongliang7
* @projectName
* @ClassName Config2RestTemplate.java
* @description: 跳过证书效验
* @createTime 2021年11月23日 09:59:00
*/
@Configuration
public class Config2RestTemplate {
@Bean
public RestTemplate restTemplate() throws Exception {
TrustStrategy acceptingTrustStrategy = (X509Certificate[] chain, String authType) -> true;
SSLContext sslContext = org.apache.http.ssl.SSLContexts.custom()
.loadTrustMaterial(null, acceptingTrustStrategy)
.build();
// SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext);
SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(createIgnoreVerifySSL(),
// 指定TLS版本
null,
// 指定算法
null,
// 取消域名验证
new HostnameVerifier() {
@Override
public boolean verify(String string, SSLSession ssls) {
return true;
}
});
CloseableHttpClient httpClient = HttpClients.custom()
.setSSLSocketFactory(csf)
.build();
HttpComponentsClientHttpRequestFactory requestFactory =
new HttpComponentsClientHttpRequestFactory();
requestFactory.setHttpClient(httpClient);
requestFactory.setReadTimeout(60 * 1000);// ms
requestFactory.setConnectTimeout(60 * 1000);// ms
// 该代码的意思是请求工厂类是否应用缓冲请求正文内部,默认值为true,当post或者put大文件的时候会造成内存溢出情况,设置为false将数据直接流入底层HttpURLConnection
requestFactory.setBufferRequestBody(false);
RestTemplate restTemplate = new RestTemplate(requestFactory);
return restTemplate;
}
/**
* 跳过证书效验的sslcontext
*
* @return
* @throws Exception
*/
private static SSLContext createIgnoreVerifySSL() throws Exception {
SSLContext sc = SSLContext.getInstance("TLS");
// 实现一个X509TrustManager接口,用于绕过验证,不用修改里面的方法
X509TrustManager trustManager = new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] paramArrayOfX509Certificate,
String paramString) throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] paramArrayOfX509Certificate,
String paramString) throws CertificateException {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}
};
sc.init(null, new TrustManager[] { trustManager }, null);
return sc;
}
}
2、OkHttpClient
package com.tencent.wemeet.gateway.restapisdk.util;
import lombok.extern.slf4j.Slf4j;
import okhttp3.OkHttpClient;
import javax.net.ssl.*;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;
/**
* @author dongliang7
* @projectName tenxun-meeting-api
* @ClassName SSLSocketClient.java
* @description: 创建 OkHttpClient 不进行SSL(证书)验证
* @createTime 2021年11月19日 09:50:00
*/
@Slf4j
public class SSLSocketClient {
public static OkHttpClient getUnsafeOkHttpClient() {
try {
// 创建不验证证书链的信任管理器
final TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
@Override
public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) {}
@Override
public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) {}
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return new java.security.cert.X509Certificate[]{};
}
}
};
if (trustAllCerts.length != 1 || !(trustAllCerts[0] instanceof X509TrustManager)) {
throw new IllegalStateException("Unexpected default trust managers:" + Arrays.toString(trustAllCerts));
}
X509TrustManager x509TrustManager = (X509TrustManager) trustAllCerts[0];
// 安装全信任信任管理器
final SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
// 使用我们完全信任的管理器创建 ssl 套接字工厂
final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
OkHttpClient.Builder builder = new OkHttpClient.Builder()
.connectTimeout(60 , TimeUnit.SECONDS).readTimeout(60 , TimeUnit.SECONDS).writeTimeout(120 , TimeUnit.SECONDS);
builder.sslSocketFactory(sslSocketFactory , x509TrustManager);
builder.hostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
OkHttpClient okHttpClient = builder.build();
return okHttpClient;
} catch (Exception e) {
log.error("创建OkHttpClient不进行SSL(证书)验证失败:{}", e.getMessage());
throw new RuntimeException(e);
}
}
}
获取OkHttpClient :
//创建 OkHttpClient 不进行SSL(证书)验证
private static final OkHttpClient okHttpClient = SSLSocketClient.getUnsafeOkHttpClient();
在minio中的运用
minioClient = MinioClient.builder()
.endpoint(minioUrl, Integer.parseInt(minioUrl.substring(minioUrl.lastIndexOf(":")+1,minioUrl.length()-1)),true)
.credentials(minioName, minioPass)
.httpClient(okHttpClient)
.build();
版权归原作者 南宫罅殇 所有, 如有侵权,请联系我们删除。