使用RestTemplate调用https接口跳过证书验证

 更新时间:2021年10月29日 11:23:20   作者:liangblog  
这篇文章主要介绍了使用RestTemplate调用https接口跳过证书验证,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

RestTemplate调用https接口跳过证书验证

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager; 
import java.nio.charset.StandardCharsets;
import java.security.cert.CertificateException; 
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.web.client.RestTemplate; 
public class NoHttpsClientUtils {
 
    /**
     * 跳过证书效验的sslcontext
     * 
     * @return
     * @throws Exception
     */
    private static SSLContext createIgnoreVerifySSL() throws Exception {
        SSLContext sc = SSLContext.getInstance("TLS");
 
        // 实现一个X509TrustManager接口,用于绕过验证,不用修改里面的方法
        X509TrustManager trustManager = new X509TrustManager() {
            @Override
            public void checkClientTrusted(java.security.cert.X509Certificate[] paramArrayOfX509Certificate,
                    String paramString) throws CertificateException {
            }
 
            @Override
            public void checkServerTrusted(java.security.cert.X509Certificate[] paramArrayOfX509Certificate,
                    String paramString) throws CertificateException {
            }
 
            @Override
            public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                return null;
            }
        };
        sc.init(null, new TrustManager[] { trustManager }, null);
        return sc;
    }
 
    /**
     * 构造RestTemplate
     * 
     * @return
     * @throws Exception
     */
    public static RestTemplate getRestTemplate() throws Exception {
        HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
        // 超时
        factory.setConnectionRequestTimeout(5000);
        factory.setConnectTimeout(5000);
        factory.setReadTimeout(5000);
        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(createIgnoreVerifySSL(),
                // 指定TLS版本
                null,
                // 指定算法
                null,
                // 取消域名验证
                new HostnameVerifier() {
                    @Override
                    public boolean verify(String string, SSLSession ssls) {
                        return true;
                    }
                });
        CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
        factory.setHttpClient(httpClient);
        RestTemplate restTemplate = new RestTemplate(factory);
        // 解决中文乱码问题
        restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8));
        return restTemplate;
    }
}

RestTemplate访问https遇到SSL证书验证错误

今天,遇到了一个SSL证书认证的问题,纠结了好久才解决,学到了很多东西,记录下来,分享给大家。

首先说一下大概的背景,我们的项目对接了第三方接口,需要向对方发送https请求。那么问题来了,https请求时需要通过SSL证书认证的,今天流程突然走不下去了,看日志发现是SSL认证的问题:

在网上找资料,解决问题有两个思路:

1.通过相关配置,跳过SSL证书验证,完成请求。

2.下载证书,将证书导入到JDK的证书管理里面。

第一种方法相当于是取巧,逃避问题,我们当然不能那么做了,我们要迎接挑战,所以小编直接pass第一条,选择第二条。

添加Https证书

下载证书

先通过浏览器将未签名验证的证书保存到本地, 具体步骤:

点击 不安全–> 证书–> 详细信息 --> 复制到文件 然后默认选择 起一个文件名 , 保存即可。

(Mac下载:Mac找不到复制的按钮。。。只能另辟蹊径了)点地址栏上的小锁,然后点证书,然后将蓝色的文件拖到要下载的文件夹即可。最好给它重命名方便使用。

导入证书

我们需要将证书导入到JDK的证书管理里面才能咋项目中使用我们刚刚下载的证书。导入命令如下:

keytool -import -noprompt -trustcacerts -alias  -keystore
 /Users/ZHONGHUI/develop/jdk-12.0.2.jdk/Contents/Home/lib/security/cacerts 
-storepass changeit -file eleme.cer

其中,因为我们用的是JDK12,跟常用的JDK8目录是不一样的,所以我的cacerts目录是:/Users/ZHONGHUI/develop/jdk-12.0.2.jdk/Contents/Home/lib/security/cacerts,如果你用的是JDK1.8或者1.7的话,那么你的cacerts在jre下的 /lib/security/下。eleme是我们给复制过来的证书取得别名,eleme.cer就是我们下载改名后的证书。changeit 是密码,如果changeit不行的话,就试试changeme,一般是changeit。

生成keystore文件

keytool -import -storepass changeit -file eleme.cer -keystore eleme.keystore

然后就会生成一个eleme.keystore文件,若权限不够,加sudo即可。将它复制到项目的类路径下。

项目中配置

将下面的RestTemplateConfig替换原来的:

package com..xxx.config; 
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
 
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.ssl.SSLContextBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter;
import org.springframework.web.client.RestTemplate; 
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
 
@Configuration
public class RestTemplateConfig { 
    @Autowired
    private FastJsonHttpMessageConverter httpMessageConverter;
 
    @Bean
    RestTemplate restTemplate() throws Exception {
    	HttpComponentsClientHttpRequestFactory factory = new                                                    
    	        HttpComponentsClientHttpRequestFactory();
    	    factory.setConnectionRequestTimeout(5 * 60 * 1000);
    	    factory.setConnectTimeout(5 * 60 * 1000);
    	    factory.setReadTimeout(5 * 60 * 1000);
    	    // https
    	    SSLContextBuilder builder = new SSLContextBuilder();
    	    KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
    	    ClassPathResource resource = new ClassPathResource("nonghang.keystore");
    	    InputStream inputStream = resource.getInputStream();
    	    keyStore.load(inputStream, null);
    	    SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(builder.build(), NoopHostnameVerifier.INSTANCE);
    	    Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
    	            .register("http", new PlainConnectionSocketFactory())
    	            .register("https", socketFactory).build();
    	    PoolingHttpClientConnectionManager phccm = new PoolingHttpClientConnectionManager(registry);
    	    phccm.setMaxTotal(200);
    	    CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(socketFactory).setConnectionManager(phccm).setConnectionManagerShared(true).build();
    	    factory.setHttpClient(httpClient);
    	    RestTemplate restTemplate = new RestTemplate(factory);
    	    List<HttpMessageConverter<?>> converters = restTemplate.getMessageConverters();
            ArrayList<HttpMessageConverter<?>> convertersValid = new ArrayList<>();
            for (HttpMessageConverter<?> converter : converters) {
                if (converter instanceof MappingJackson2HttpMessageConverter ||
                    converter instanceof MappingJackson2XmlHttpMessageConverter) {
                    continue;
                }
                convertersValid.add(converter);
            }
            convertersValid.add(httpMessageConverter);
            restTemplate.setMessageConverters(convertersValid);
    	    inputStream.close();
        return restTemplate;
    }
}
 

好啦,万事俱备只欠东风,自信满满的试了一下,发现还是行不通,深受打击的我决定还是去看看导致这类报错的原因。

从根源出发,https的socket工作原理是怎样的?

https的socket工作原理流程图如下:

那么,什么是SSL证书?

SSL 证书就是遵守 SSL协议,由受信任的数字证书颁发机构CA,在验证服务器身份后颁发,具有服务器身份验证和数据传输加密功能。

首先,要知道导致报这个异常的原因不仅仅是因为证书校验不通过。

1.在我们通过https链接服务器时,服务器会给我们返回一个证书,这个证书可能经过CA认证,也可能是未认证的自制证书,客户端拿到这个证书后会对这个证书进行验证,如果是经过CA验证的证书,自然证书校验就能通过,自制证书自然就校验不同过,从而导致上边的异常。

2.证书校验通过后,还需要校验访问的域名是否和证书指定的域名是否匹配。未匹配也会导致如上异常。

3.上边两步都校验通过了才开始进行握手,但握手也有可能失败,从而导致上边的异常。

以上三个步骤中任何一个出了问题,都会连接失败。

首先,我们获取的证书是经过CA认证的,理应不会出现不通过的情况,第三方的域名也是没有问题的。那么到底是哪里出了问题呢?

后来我们从网络组那边了解到,他们那边对最近做了大的改动,之前的proxy都要重新加,加的时候把我们的给漏掉了。。。。辛苦大半天,被坑惨了啊。。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • java数据结构和算法中哈希表知识点详解

    java数据结构和算法中哈希表知识点详解

    在本篇文章里小编给大家分享了关于java数据结构和算法中哈希表的相关知识点内容,需要的朋友们学习下。
    2019-06-06
  • Java中常用数据类型的输入输出详解

    Java中常用数据类型的输入输出详解

    本文主要介绍了Java中几个常用的数据类型是如何输入和输出的,例如:Char型、int型、double型、数组、字符串等,对我们学习java有一定的帮助,感兴趣的小伙伴可以跟随小编一起学习学习
    2021-12-12
  • Spring事务失效场景的详细整理

    Spring事务失效场景的详细整理

    Spring 事务的传播特性说的是,当多个事务同时存在的时候,Spring 如何处理这些事务的特性,下面这篇文章主要给大家介绍了关于Spring事务失效场景的相关资料,需要的朋友可以参考下
    2022-02-02
  • 详细分析Java并发集合ArrayBlockingQueue的用法

    详细分析Java并发集合ArrayBlockingQueue的用法

    这篇文章主要介绍了详细分析Java并发集合ArrayBlockingQueue的用法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-04-04
  • 在SpringBoot项目中如何实现线程池的动态监控

    在SpringBoot项目中如何实现线程池的动态监控

    Spring Boot因其简便、高效的特点广受开发者喜爱,在复杂的业务场景下,如何确保Spring Boot应用的高性能和稳定性成为了一个关键问题,其中,线程池的管理策略直接影响到系统的吞吐量和资源利用效率,本文将重点探讨在Spring Boot项目中,如何实现线程池的动态监控
    2023-10-10
  • JSch教程使用sftp协议实现服务器文件载操作

    JSch教程使用sftp协议实现服务器文件载操作

    这篇文章主要为大家介绍了JSch如何使用sftp协议实现服务器文件上传下载操作,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步
    2022-03-03
  • Java常用线程池原理及使用方法解析

    Java常用线程池原理及使用方法解析

    这篇文章主要介绍了Java常用线程池原理及使用方法解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-07-07
  • Spring整合quartz做定时任务的示例代码

    Spring整合quartz做定时任务的示例代码

    这篇文章主要介绍了在spring项目使用quartz做定时任务,首先我这里的项目已经是一个可以跑起来的完整项目,web.xml里面的配置我就不贴出来了,具体实例代码跟随小编一起看看吧
    2022-01-01
  • java交换排序之鸡尾酒排序实现方法

    java交换排序之鸡尾酒排序实现方法

    这篇文章主要介绍了java交换排序之鸡尾酒排序实现方法,实例分析了排序的原理与相关的实现技巧,需要的朋友可以参考下
    2015-02-02
  • java解析dbf之通过javadbf包生成和读取dbf文件

    java解析dbf之通过javadbf包生成和读取dbf文件

    这篇文章主要介绍了java通过javadbf读取和生成DBF文件的方法,大家参考使用吧
    2014-01-01

最新评论