springboot基于keytool實現(xiàn)https的雙向認證示例教程
一、環(huán)境準備
服務器信息如下:
| 操作系統(tǒng) | 說明 |
| server-one | 服務器1 |
| server-two | 服務器2 |
二、keytool命令解釋
-genkey 表示要創(chuàng)建一個新的密鑰。
-alias 表示 keystore 的別名。
-keyalg 表示使用的加密算法是 RSA ,一種非對稱加密算法。
-keysize 表示密鑰的長度。
-keystore 表示生成的密鑰存放位置。
-validity 表示密鑰的有效時間,單位為天。-keypass 私鑰訪問密碼:123456
-storepass keystone文件訪問密碼:123456
刪除導入的信任證書
keytool -delete -alias 刪除證書的別名 -keystore 信任庫 keytool -delete -alias server-one -keystore /home/keytool/trustKeys.p12
三、服務器server-one生成密鑰 服務器
1生成TrustStore(信任庫.P12)
keytool -genkey -alias trustkeys -storetype PKCS12 -keyalg RSA -keysize 2048 -keystore /home/keytool/trustKeys.p12 -validity 36500

服務器1生成客戶端密鑰(.P12)
keytool -genkey -alias server-one -storetype PKCS12 -keyalg RSA -keysize 2048 -keystore /home/keytool/server-one.p12 -validity 36500
服務器1導出客戶端公鑰(.cer)
keytool -keystore /home/keytool/server-one.p12 -export -alias server-one -file /home/keytool/server-one-publicKey.cer
添加客戶端(服務器2)公鑰到服務器1的信任庫(雙向認證需要操作此步驟)
keytool -import -alias server-two -v -file /home/keytool/server-two-publicKey.cer -keystore /home/keytool/trustKeys.p12

從服務器1生成客戶端密鑰(.P12)文件中導出私鑰文件(.key)
openssl pkcs12 -in /home/keytool/server-one.p12 -nodes -nocerts -out /home/keytool/server-one.key
從服務器1導出的客戶端公鑰(.cer)文件中導出公鑰文件(.pem)
openssl x509 -inform der -in /home/keytool/server-one-publicKey.cer -out /home/keytool/server-one.pem
四、服務器server-two生成密鑰(參考服務器1)
服務器2生成TrustStore(信任庫.P12)
keytool -genkey -alias trustkeys -storetype PKCS12 -keyalg RSA -keysize 2048 -keystore /home/keytool/trustKeys.p12 -validity 36500
服務器2生成客戶端密鑰(.P12)
keytool -genkey -alias server-two -storetype PKCS12 -keyalg RSA -keysize 2048 -keystore /home/keytool/server-two.p12 -validity 36500
服務器2導出客戶端公鑰(.cer)
keytool -keystore /home/keytool/server-two.p12 -export -alias server-one -file /home/keytool/server-two-publicKey.cer
添加客戶端(服務器1)的公鑰到服務器2的信任庫(雙向認證需要操作此步驟)
keytool -import -alias server-one -v -file /home/keytool/server-one-publicKey.cer -keystore /home/keytool/trustKeys.p12
從服務器2生成客戶端密鑰(.P12)文件中導出私鑰文件(.key)
openssl pkcs12 -in /home/keytool/server-two.p12 -nodes -nocerts -out /home/keytool/server-two.key
從服務器2導出的客戶端公鑰(.cer)文件中導出公鑰文件(.pem)
openssl x509 -inform der -in /home/keytool/server-two-publicKey.cer -out /home/keytool/server-two.pem
五、配置SpringBoot支持https
1、服務器1配置文件application.properties
#開啟ssl server.ssl.enabled=true #配置的值 need雙向驗證 none不驗證客戶端 want會驗證,但不強制驗證,即驗證失敗也可以成功建立連接 server.ssl.client-auth=need #協(xié)議 #server.ssl.protocol=TLS #服務通信證書 server.ssl.key-store=classpath:ssl/server-one.p12 #密鑰密碼 #server.ssl.key-password=123456 #證書密碼 server.ssl.key-store-password=123456 #證書格式 server.ssl.key-store-type=PKCS12 #證書別名 server.ssl.keyAlias=server-one #信任庫文件 server.ssl.trust-store=classpath:ice-ca/trustKeys.p12 #信任庫密碼 server.ssl.trust-store-password=123456 #信任庫類型 server.ssl.trust-store-type=PKCS12
2、服務器2配置文件application.properties
#開啟ssl server.ssl.enabled=true #配置的值 need雙向驗證 none不驗證客戶端 want會驗證,但不強制驗證,即驗證失敗也可以成功建立連接 server.ssl.client-auth=need #協(xié)議 #server.ssl.protocol=TLS #服務通信證書 server.ssl.key-store=classpath:ssl/server-two.p12 #密鑰密碼 #server.ssl.key-password=123456 #證書密碼 server.ssl.key-store-password=123456 #證書格式 server.ssl.key-store-type=PKCS12 #證書別名 server.ssl.keyAlias=server-two #信任庫文件 server.ssl.trust-store=classpath:ice-ca/trustKeys.p12 #信任庫密碼 server.ssl.trust-store-password=123456 #信任庫類型 server.ssl.trust-store-type=PKCS12
3、拷貝相應密鑰到resources目錄下

4、pom.xml配置文件添加配置項如下
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
<include>ssl/server-one.p12</include>
<include>ice-ca/trustKeys.p12</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
</resource>
</resources>六、配置RestTemplate工具類
1、pom添加httpclient支持
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.13</version>
</dependency>2、設(shè)置RestTemplate支持https請求
import lombok.extern.slf4j.Slf4j;
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.springframework.beans.factory.annotation.Value;
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.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.security.*;
import java.security.cert.CertificateException;
import java.time.Duration;
/**
* HTTPS通信雙向認證工具類
*
* @author xiwh
*/
@Configuration
@Slf4j
public class RestTemplateConfig {
@Value("${server.ssl.key-store-type}")
String clientKeyType;
@Value("${server.ssl.key-store}")
String clientPath;
@Value("${server.ssl.key-store-password}")
String clientPass;
@Value("${server.ssl.trust-store-type}")
String trustKeyType;
@Value("${server.ssl.trust-store}")
String trustPath;
@Value("${server.ssl.trust-store-password}")
String trustPass;
@Bean
public RestTemplate restTemplate() {
RestTemplate restTemplate = null;
try {
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
// 客戶端證書類型
KeyStore clientStore = KeyStore.getInstance(clientKeyType);
// 加載客戶端證書,即自己的私鑰
InputStream keyStream = getClass().getClassLoader().getResourceAsStream(clientPath);
clientStore.load(keyStream, clientPass.toCharArray());
// 創(chuàng)建密鑰管理工廠實例
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
// 初始化客戶端密鑰庫
keyManagerFactory.init(clientStore, clientPass.toCharArray());
KeyManager[] keyManagers = keyManagerFactory.getKeyManagers();
// 創(chuàng)建信任庫管理工廠實例
TrustManagerFactory trustManagerFactory = TrustManagerFactory
.getInstance(TrustManagerFactory.getDefaultAlgorithm());
KeyStore trustStore = KeyStore.getInstance(trustKeyType);
InputStream trustStream = getClass().getClassLoader().getResourceAsStream(trustPath);
// 加載信任證書
trustStore.load(trustStream, trustPass.toCharArray());
// 初始化信任庫
trustManagerFactory.init(trustStore);
//雙向校驗 校驗服務端證書是否在信任庫
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
// 建立TLS連接
SSLContext sslContext = SSLContext.getInstance("TLS");
// 初始化SSLContext
sslContext.init(keyManagers, trustManagers, new SecureRandom());
// INSTANCE 忽略域名檢查
SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE);
// 創(chuàng)建httpClient對象
CloseableHttpClient httpclient = HttpClients
.custom()
.setSSLSocketFactory(sslConnectionSocketFactory)
.setSSLHostnameVerifier(new NoopHostnameVerifier())
.build();
requestFactory.setHttpClient(httpclient);
requestFactory.setConnectTimeout((int) Duration.ofSeconds(15).toMillis());
restTemplate = new RestTemplate(requestFactory);
} catch (KeyManagementException | FileNotFoundException | NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (KeyStoreException | CertificateException | UnrecoverableKeyException | IOException e) {
e.printStackTrace();
}
return restTemplate;
}
}3、測試代碼
服務器1(server-one)請求接口代碼
@Test
public void testHttps() {
String url = "https://127.0.0.1:8077/httpsTest";
ResponseEntity<String> forEntity = restTemplate.getForEntity(url, String.class);
System.out.println(forEntity.toString());
}服務器2(server-two)controller代碼
/**
* https測試方法
*
* @return
*/
@ApiOperation("https測試方法")
@GetMapping("/httpsTest")
public Result httpsTest() {
log.info("服務器server-two響應成功!");
return Result.SUCCESS();
}服務器2(server-two)執(zhí)行結(jié)果
<200,{"code":1,"success":true,"msg":"操作成功","data":null}>
七、Nginx配置ssl證書
server {
#監(jiān)聽前端訪問端口
listen 9028 ssl;
#服務器地址
server_name 47.104.239.238;
charset utf-8;
client_max_body_size 20M;
#雙向認證 開啟校驗客戶端
#ssl_verify_client on;
#server公鑰 或 阿里云證書 一般是crt文件
ssl_certificate /home/keytool/server.pem;
#server私鑰 或 阿里云證書 一般是key文件
ssl_certificate_key /home/keytool/server.key;
#雙向認證 客戶端公鑰
#ssl_client_certificate /home/keytool/server.pem;
#支持ssl協(xié)議版本
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
#配置服務器可使用的加密算法
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
# 指定服務器密碼算法在優(yōu)先于客戶端密碼算法時,使用 SSLv3 和 TLS 協(xié)議
ssl_prefer_server_ciphers on;
ssl_session_timeout 5m;
#前端請求后端接口
location /prod-api/ {
proxy_pass https://47.104.239.238:8077/;
proxy_set_header Host $proxy_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Nginx-Proxt true;
proxy_set_header HTTP_X_FORWORDED_FOR $remote_addr;
proxy_ssl_certificate /home/keytool/server.pem;
proxy_ssl_certificate_key /home/keytool/server.key;
proxy_ssl_protocols TLSv1 TLSv1.1 TLSv1.2 SSLv2 SSLv3 ;
proxy_ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
proxy_ssl_session_reuse off;
proxy_ssl_server_name on;
proxy_redirect off;
}
#前端包目錄
location / {
root /mnt/project/sinotmemc/dist;
try_files $uri $uri/ /index.html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}參考資料:
spring boot 使用RestTemplate通過證書認證訪問https實現(xiàn)SSL請求
到此這篇關(guān)于springboot基于keytool實現(xiàn)https的雙向認證的文章就介紹到這了,更多相關(guān)springboot https雙向認證內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
在IntelliJ IDEA中多線程并發(fā)代碼的調(diào)試方法詳解
這篇文章主要介紹了在IntelliJ IDEA中多線程并發(fā)代碼的調(diào)試方法,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-08-08
解決Springboot 2 的@RequestParam接收數(shù)組異常問題
這篇文章主要介紹了解決Springboot 2 的@RequestParam接收數(shù)組異常問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-08-08
Java實現(xiàn)批量向mysql寫入數(shù)據(jù)的方法
這篇文章主要介紹了Java實現(xiàn)批量向mysql寫入數(shù)據(jù)的方法,涉及java基于JDBC連接mysql數(shù)據(jù)庫及寫入數(shù)據(jù)的相關(guān)操作技巧,非常簡單實用,需要的朋友可以參考下2017-12-12
SpringMVC+EasyUI實現(xiàn)頁面左側(cè)導航菜單功能
這篇文章主要介紹了SpringMVC+EasyUI實現(xiàn)頁面左側(cè)導航菜單功能,本文通過實例代碼給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下2019-09-09

