• 解决远程调用三方接口:javax.net.ssl.SSLHandshakeException报错


    一、前言

    最近在对接腾讯会议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();
  • 相关阅读:
    ansible——playbook conditions条件判断
    ansible——playbook lookups从插件加载变量
    ansible——playbook循环
    lombok注解
    集合与集合取笛卡尔积
    List排列组合
    synchronized初识
    java IO与NIO
    文件I/O和标准I/O
    双数据源配置
  • 原文地址:https://www.cnblogs.com/dongl961230/p/15594627.html
Copyright © 2020-2023  润新知