您好,登錄后才能下訂單哦!
這篇文章將為大家詳細(xì)講解有關(guān)如何使用RestTemplate調(diào)用https接口跳過(guò)證書驗(yàn)證,小編覺(jué)得挺實(shí)用的,因此分享給大家做個(gè)參考,希望大家閱讀完這篇文章后可以有所收獲。
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 { /** * 跳過(guò)證書效驗(yàn)的sslcontext * * @return * @throws Exception */ private static SSLContext createIgnoreVerifySSL() throws Exception { SSLContext sc = SSLContext.getInstance("TLS"); // 實(shí)現(xiàn)一個(gè)X509TrustManager接口,用于繞過(guò)驗(yàn)證,不用修改里面的方法 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; } /** * 構(gòu)造RestTemplate * * @return * @throws Exception */ public static RestTemplate getRestTemplate() throws Exception { HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(); // 超時(shí) factory.setConnectionRequestTimeout(5000); factory.setConnectTimeout(5000); factory.setReadTimeout(5000); SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(createIgnoreVerifySSL(), // 指定TLS版本 null, // 指定算法 null, // 取消域名驗(yàn)證 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); // 解決中文亂碼問(wèn)題 restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8)); return restTemplate; } }
今天,遇到了一個(gè)SSL證書認(rèn)證的問(wèn)題,糾結(jié)了好久才解決,學(xué)到了很多東西,記錄下來(lái),分享給大家。
首先說(shuō)一下大概的背景,我們的項(xiàng)目對(duì)接了第三方接口,需要向?qū)Ψ桨l(fā)送https請(qǐng)求。那么問(wèn)題來(lái)了,https請(qǐng)求時(shí)需要通過(guò)SSL證書認(rèn)證的,今天流程突然走不下去了,看日志發(fā)現(xiàn)是SSL認(rèn)證的問(wèn)題:
在網(wǎng)上找資料,解決問(wèn)題有兩個(gè)思路:
1.通過(guò)相關(guān)配置,跳過(guò)SSL證書驗(yàn)證,完成請(qǐng)求。
2.下載證書,將證書導(dǎo)入到JDK的證書管理里面。
第一種方法相當(dāng)于是取巧,逃避問(wèn)題,我們當(dāng)然不能那么做了,我們要迎接挑戰(zhàn),所以小編直接pass第一條,選擇第二條。
先通過(guò)瀏覽器將未簽名驗(yàn)證的證書保存到本地, 具體步驟:
點(diǎn)擊 不安全–> 證書–> 詳細(xì)信息 --> 復(fù)制到文件 然后默認(rèn)選擇 起一個(gè)文件名 , 保存即可。
(Mac下載:Mac找不到復(fù)制的按鈕。。。只能另辟蹊徑了)點(diǎn)地址欄上的小鎖,然后點(diǎn)證書,然后將藍(lán)色的文件拖到要下載的文件夾即可。最好給它重命名方便使用。
我們需要將證書導(dǎo)入到JDK的證書管理里面才能咋項(xiàng)目中使用我們剛剛下載的證書。導(dǎo)入命令如下:
keytool -import -noprompt -trustcacerts -alias -keystore /Users/ZHONGHUI/develop/jdk-12.0.2.jdk/Contents/Home/lib/security/cacerts -storepass changeit -file eleme.cer
其中,因?yàn)槲覀冇玫氖荍DK12,跟常用的JDK8目錄是不一樣的,所以我的cacerts目錄是:/Users/ZHONGHUI/develop/jdk-12.0.2.jdk/Contents/Home/lib/security/cacerts,如果你用的是JDK1.8或者1.7的話,那么你的cacerts在jre下的 /lib/security/下。eleme是我們給復(fù)制過(guò)來(lái)的證書取得別名,eleme.cer就是我們下載改名后的證書。changeit 是密碼,如果changeit不行的話,就試試changeme,一般是changeit。
keytool -import -storepass changeit -file eleme.cer -keystore eleme.keystore
然后就會(huì)生成一個(gè)eleme.keystore文件,若權(quán)限不夠,加sudo即可。將它復(fù)制到項(xiàng)目的類路徑下。
將下面的RestTemplateConfig替換原來(lái)的:
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; } }
好啦,萬(wàn)事俱備只欠東風(fēng),自信滿滿的試了一下,發(fā)現(xiàn)還是行不通,深受打擊的我決定還是去看看導(dǎo)致這類報(bào)錯(cuò)的原因。
從根源出發(fā),https的socket工作原理是怎樣的?
https的socket工作原理流程圖如下:
那么,什么是SSL證書?
SSL 證書就是遵守 SSL協(xié)議,由受信任的數(shù)字證書頒發(fā)機(jī)構(gòu)CA,在驗(yàn)證服務(wù)器身份后頒發(fā),具有服務(wù)器身份驗(yàn)證和數(shù)據(jù)傳輸加密功能。
首先,要知道導(dǎo)致報(bào)這個(gè)異常的原因不僅僅是因?yàn)樽C書校驗(yàn)不通過(guò)。
1.在我們通過(guò)https鏈接服務(wù)器時(shí),服務(wù)器會(huì)給我們返回一個(gè)證書,這個(gè)證書可能經(jīng)過(guò)CA認(rèn)證,也可能是未認(rèn)證的自制證書,客戶端拿到這個(gè)證書后會(huì)對(duì)這個(gè)證書進(jìn)行驗(yàn)證,如果是經(jīng)過(guò)CA驗(yàn)證的證書,自然證書校驗(yàn)就能通過(guò),自制證書自然就校驗(yàn)不同過(guò),從而導(dǎo)致上邊的異常。
2.證書校驗(yàn)通過(guò)后,還需要校驗(yàn)訪問(wèn)的域名是否和證書指定的域名是否匹配。未匹配也會(huì)導(dǎo)致如上異常。
3.上邊兩步都校驗(yàn)通過(guò)了才開(kāi)始進(jìn)行握手,但握手也有可能失敗,從而導(dǎo)致上邊的異常。
關(guān)于“如何使用RestTemplate調(diào)用https接口跳過(guò)證書驗(yàn)證”這篇文章就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,使各位可以學(xué)到更多知識(shí),如果覺(jué)得文章不錯(cuò),請(qǐng)把它分享出去讓更多的人看到。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。