springboot實(shí)現(xiàn)https雙向傳輸協(xié)議的示例代碼
1.https 雙向傳輸協(xié)議概念
1.1. 單向認(rèn)證
- 我們?cè)谕ǔTL(fǎng)問(wèn)一個(gè)網(wǎng)站,例如百度。這是一個(gè)單向的TLS認(rèn)證。
- 具體的過(guò)程為:
- 服務(wù)器發(fā)送證書(shū)給客戶(hù)端。
- 客戶(hù)端驗(yàn)證證書(shū)有效之后,客戶(hù)端和服務(wù)器協(xié)商出一個(gè)對(duì)稱(chēng)加密密鑰。
- 由服務(wù)端的私鑰加密,并發(fā)送給客戶(hù)端。
- 客戶(hù)端收到之后再用公鑰解密這個(gè)對(duì)稱(chēng)密鑰。然后就開(kāi)始用對(duì)稱(chēng)密鑰加密傳輸?shù)臄?shù)據(jù)。
- 特征:
- 服務(wù)端并不校驗(yàn)客戶(hù)端的合法性,來(lái)者不拒,絕大部分的網(wǎng)站都是這種類(lèi)型。
- 只有客戶(hù)端校驗(yàn)服務(wù)器端的合法性。
1.2. 雙向認(rèn)證
- 有時(shí)候我們?cè)谝恍┌踩砸筝^高的場(chǎng)景下,服務(wù)器也需要來(lái)校驗(yàn)客戶(hù)端的合法性。
- 具體的過(guò)程為:
- 在客戶(hù)端驗(yàn)證了服務(wù)器證書(shū)的合法性之后,客戶(hù)端需要帶上自己的證書(shū)發(fā)送給服務(wù)器。
- 服務(wù)器收到證書(shū)之后,比對(duì)服務(wù)器在信任鏈中是否信任了客戶(hù)端的證書(shū)。
- 如果信任,則服務(wù)端校驗(yàn)客戶(hù)端合法。
- 如果證書(shū)不在服務(wù)端的受信列表上,則拒絕服務(wù)。
- 這樣子其實(shí)就是建立了一條雙向認(rèn)證的TLS傳輸通道。即互相校驗(yàn)證書(shū)。
1.3. 非對(duì)稱(chēng)加密交互流程
- 如果用到的是非對(duì)稱(chēng)加密,那么你和第三方之間就有兩對(duì)公私鑰,各自持有對(duì)方的公鑰和自己的私鑰。網(wǎng)絡(luò)通訊中我們一般用自己的私鑰將報(bào)文加簽,用第三方提供的公鑰將報(bào)文中涉及安全隱私的部分加密,然后第三方會(huì)用我們提供公鑰進(jìn)行驗(yàn)簽,驗(yàn)簽通過(guò)后再用他們自己的私鑰將報(bào)文加密部分解密;
1.4. csr文件
- CSR 即證書(shū)簽名申請(qǐng)(Certificate Signing Request),獲取 SSL 證書(shū),需要先生成 CSR 文件并提交給證書(shū)頒發(fā)機(jī)構(gòu)(CA)。CSR 包含了用于簽發(fā)證書(shū)的公鑰、用于辨識(shí)的名稱(chēng)信息(Distinguished Name)(例如域名)、真實(shí)性和完整性保護(hù)(例如數(shù)字簽名),通常從 Web 服務(wù)器生成 CSR;
- 證書(shū)申請(qǐng)者只要把CSR文件提交給證書(shū)頒發(fā)機(jī)構(gòu)后,證書(shū)頒發(fā)機(jī)構(gòu)使用其根證書(shū)私鑰簽名就生成了證書(shū)公鑰文件,也就是頒發(fā)給用戶(hù)的證書(shū)。
1.5. 生成證書(shū)相關(guān)流程
# 1. 生成客戶(hù)端csr和私鑰key 執(zhí)行這個(gè)指令后會(huì)生成csr文件和私鑰key openssl req -new -nodes -sha256 -newkey rsa:2048 -keyout privateKey.key -out request.csr # 生成csr文件后,將csr文件發(fā)送給甲方,甲方簽發(fā)了ca.pem給我們 # 后續(xù)訪(fǎng)問(wèn)甲方接口,就一直攜帶ca.pem和本地私鑰 用于傳輸過(guò)程中的文件和數(shù)據(jù)加密;
2. 使用springboot實(shí)現(xiàn)https雙向傳輸協(xié)議實(shí)例
2.1. 配置證書(shū)和私鑰路徑
- 在配置文件中配置證書(shū)和私鑰路徑,使得項(xiàng)目能夠訪(fǎng)問(wèn)到;
- ca.pem,privateKey.key
2.2. 調(diào)用請(qǐng)求方法
// 調(diào)用方法
resp = apiService.request(true, POST, url, req);2.3. ApiService層方法
@Override
public String request(Boolean ssl, HttpMethod method, String url, String reqBody) throws Exception {
// 調(diào)用下方的request方法
return request(ssl, method, url, null, reqBody);
}
// 雙向認(rèn)證請(qǐng)求
@Override
public String request(Boolean ssl, HttpMethod method, String url, MultiValueMap<String, String> params,
String reqBody)
throws Exception {
logger.info("request url to server =====> {}", url);
logger.info("request body to server =====> {}", reqBody);
// 根據(jù)實(shí)際需求添加請(qǐng)求頭
HttpHeaders headers = new HttpHeaders();
headers.set("token", "");
ResponseEntity<String> resp = sslService.request(ssl, url, method, headers, params, reqBody);
String respBody = resp.getBody();
logger.info("resp body from server =====> {}", respBody);
return respBody;
}
2.4. sslService類(lèi)中方法
@Override
public ResponseEntity<String> request(Boolean ssl, String url, HttpMethod method, HttpHeaders headers,
MultiValueMap<String, String> params, String reqBody) throws Exception {
HttpsClient client = !ssl ? new HttpsClient(ssl)
: new HttpsClient(ssl, "證書(shū)路徑", "私鑰路徑");
return RestClientUtil.request(client, url, method, headers, params, reqBody);
}
2.5. HTTPS通信雙向認(rèn)證工具類(lèi)
/**
* @Description //HTTPS通信雙向認(rèn)證工具類(lèi)
**/
@Data
public class HttpsClient {
// true-啟用雙向認(rèn)證,false-不啟用
private boolean ssl;
// 服務(wù)端公鑰
private String serverPem;
// 客戶(hù)端私鑰
private String clientSK;
public HttpsClient() {
}
public HttpsClient(Boolean ssl) {
this.ssl = ssl;
}
public HttpsClient(Boolean ssl, String serverPem, String clientSK) {
this.ssl = ssl;
this.serverPem = serverPem;
this.clientSK = clientSK;
}
}
2.6. RestClientUtil類(lèi)中方法
public static ResponseEntity<String> request(HttpsClient client, String url, HttpMethod method,
HttpHeaders httpHeaders,
MultiValueMap<String, String> params,
String reqBody) throws Exception {
httpHeaders.set("Content-Type", "application/json; charset=utf-8");
HttpEntity<?> requestEntity = new HttpEntity<>(reqBody, httpHeaders);
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(url).queryParams(params);
// UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(url).queryParams(params);
RestTemplate rest = client.isSsl()
? new RestTemplate(HttpsClientUtil.rsaHttpComponentsClientHttpRequestFactory(client))
: new RestTemplate(generateHttpRequestFactory());
return rest.exchange(builder.toUriString(), method, requestEntity, String.class);
}
/**
* 忽略SSL證書(shū)
*
* @return
*/
private static HttpComponentsClientHttpRequestFactory generateHttpRequestFactory() {
TrustStrategy acceptingTrustStrategy = (x509Certificates, authType) -> true;
SSLContext sslContext = null;
try {
sslContext = SSLContexts.custom().loadTrustMaterial(null, acceptingTrustStrategy).build();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
} catch (KeyStoreException e) {
e.printStackTrace();
}
SSLConnectionSocketFactory connectionSocketFactory = new SSLConnectionSocketFactory(sslContext,
new NoopHostnameVerifier());
HttpClientBuilder httpClientBuilder = HttpClients.custom();
httpClientBuilder.setSSLSocketFactory(connectionSocketFactory);
CloseableHttpClient httpClient = httpClientBuilder.build();
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
factory.setHttpClient(httpClient);
return factory;
}
2.7. HttpsClientUtil類(lèi)中方法
public static HttpComponentsClientHttpRequestFactory rsaHttpComponentsClientHttpRequestFactory(HttpsClient client)
throws Exception {
// 獲取httpClient對(duì)象,防止重復(fù)創(chuàng)建--讀取證書(shū)信息,對(duì)象生成后不做其他操作所以未加鎖
if (httpClient == null) {
httpClient = createCloseableHttpClientByRsa(client);
}
HttpComponentsClientHttpRequestFactory httpsFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
// httpsFactory.setReadTimeout(5000);
// httpsFactory.setConnectTimeout(5000);
httpsFactory.setReadTimeout(60 * 1000);
httpsFactory.setConnectTimeout(60 * 1000);
return httpsFactory;
}到此這篇關(guān)于springboot實(shí)現(xiàn)https雙向傳輸協(xié)議的示例代碼的文章就介紹到這了,更多相關(guān)springboot https雙向傳輸內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
客戶(hù)端設(shè)置超時(shí)時(shí)間真的很重要
今天小編就為大家分享一篇關(guān)于客戶(hù)端設(shè)置超時(shí)時(shí)間真的很重要,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2018-12-12
Java經(jīng)典排序算法之歸并排序?qū)崿F(xiàn)代碼
這篇文章主要介紹了Java經(jīng)典排序算法之歸并排序?qū)崿F(xiàn)代碼,歸并排序是建立在歸并操作上的一種有效的排序算法,該算法是采用分治法的一個(gè)非常典型的應(yīng)用,將已有序的子序列合并,得到完全有序的序列,需要的朋友可以參考下2023-10-10
Java中報(bào)錯(cuò)org.springframework.jdbc.UncategorizedSQLException的多種
本文主要介紹了Java中報(bào)錯(cuò)org.springframework.jdbc.UncategorizedSQLException的多種解決方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-06-06
關(guān)于@Scheduled參數(shù)及cron表達(dá)式解釋
這篇文章主要介紹了關(guān)于@Scheduled參數(shù)及cron表達(dá)式解釋?zhuān)哂泻芎玫膮⒖純r(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12
使用Java編寫(xiě)控制JDBC連接、執(zhí)行及關(guān)閉的工具類(lèi)
這篇文章主要介紹了如何使用Java來(lái)編寫(xiě)控制JDBC連接、執(zhí)行及關(guān)閉的程序,包括一個(gè)針對(duì)各種數(shù)據(jù)庫(kù)通用的釋放資源的工具類(lèi)的寫(xiě)法,需要的朋友可以參考下2016-03-03
Java調(diào)用ChatGPT(基于SpringBoot和Vue)實(shí)現(xiàn)可連續(xù)對(duì)話(huà)和流式輸出的ChatGPT API
這篇文章主要介紹了Java調(diào)用ChatGPT(基于SpringBoot和Vue),實(shí)現(xiàn)可連續(xù)對(duì)話(huà)和流式輸出的ChatGPT API(可自定義實(shí)現(xiàn)AI助手),文中代碼示例介紹的非常詳細(xì),感興趣的朋友可以參考下2023-04-04
Java Set接口及常用實(shí)現(xiàn)類(lèi)總結(jié)
Collection的另一個(gè)子接口就是Set,他并沒(méi)有我們List常用,并且自身也沒(méi)有一些額外的方法,全是繼承自Collection中的,因此我們還是簡(jiǎn)單總結(jié)一下,包括他的常用實(shí)現(xiàn)類(lèi)HashSet、LinkedHashSet、TreeSet的總結(jié)2023-01-01
Java編程實(shí)現(xiàn)NBA賽事接口調(diào)用實(shí)例代碼
這篇文章主要介紹了Java編程實(shí)現(xiàn)NBA賽事接口調(diào)用實(shí)例代碼,具有一定參考價(jià)值,需要的朋友可以了解下。2017-11-11

