springboot基于keytool實現(xiàn)https的雙向認證示例教程
一、環(huán)境準備
服務(wù)器信息如下:
操作系統(tǒng) | 說明 |
server-one | 服務(wù)器1 |
server-two | 服務(wù)器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
三、服務(wù)器server-one生成密鑰 服務(wù)器
1生成TrustStore(信任庫.P12)
keytool -genkey -alias trustkeys -storetype PKCS12 -keyalg RSA -keysize 2048 -keystore /home/keytool/trustKeys.p12 -validity 36500
服務(wù)器1生成客戶端密鑰(.P12)
keytool -genkey -alias server-one -storetype PKCS12 -keyalg RSA -keysize 2048 -keystore /home/keytool/server-one.p12 -validity 36500
服務(wù)器1導出客戶端公鑰(.cer)
keytool -keystore /home/keytool/server-one.p12 -export -alias server-one -file /home/keytool/server-one-publicKey.cer
添加客戶端(服務(wù)器2)公鑰到服務(wù)器1的信任庫(雙向認證需要操作此步驟)
keytool -import -alias server-two -v -file /home/keytool/server-two-publicKey.cer -keystore /home/keytool/trustKeys.p12
從服務(wù)器1生成客戶端密鑰(.P12)文件中導出私鑰文件(.key)
openssl pkcs12 -in /home/keytool/server-one.p12 -nodes -nocerts -out /home/keytool/server-one.key
從服務(wù)器1導出的客戶端公鑰(.cer)文件中導出公鑰文件(.pem)
openssl x509 -inform der -in /home/keytool/server-one-publicKey.cer -out /home/keytool/server-one.pem
四、服務(wù)器server-two生成密鑰(參考服務(wù)器1)
服務(wù)器2生成TrustStore(信任庫.P12)
keytool -genkey -alias trustkeys -storetype PKCS12 -keyalg RSA -keysize 2048 -keystore /home/keytool/trustKeys.p12 -validity 36500
服務(wù)器2生成客戶端密鑰(.P12)
keytool -genkey -alias server-two -storetype PKCS12 -keyalg RSA -keysize 2048 -keystore /home/keytool/server-two.p12 -validity 36500
服務(wù)器2導出客戶端公鑰(.cer)
keytool -keystore /home/keytool/server-two.p12 -export -alias server-one -file /home/keytool/server-two-publicKey.cer
添加客戶端(服務(wù)器1)的公鑰到服務(wù)器2的信任庫(雙向認證需要操作此步驟)
keytool -import -alias server-one -v -file /home/keytool/server-one-publicKey.cer -keystore /home/keytool/trustKeys.p12
從服務(wù)器2生成客戶端密鑰(.P12)文件中導出私鑰文件(.key)
openssl pkcs12 -in /home/keytool/server-two.p12 -nodes -nocerts -out /home/keytool/server-two.key
從服務(wù)器2導出的客戶端公鑰(.cer)文件中導出公鑰文件(.pem)
openssl x509 -inform der -in /home/keytool/server-two-publicKey.cer -out /home/keytool/server-two.pem
五、配置SpringBoot支持https
1、服務(wù)器1配置文件application.properties
#開啟ssl server.ssl.enabled=true #配置的值 need雙向驗證 none不驗證客戶端 want會驗證,但不強制驗證,即驗證失敗也可以成功建立連接 server.ssl.client-auth=need #協(xié)議 #server.ssl.protocol=TLS #服務(wù)通信證書 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、服務(wù)器2配置文件application.properties
#開啟ssl server.ssl.enabled=true #配置的值 need雙向驗證 none不驗證客戶端 want會驗證,但不強制驗證,即驗證失敗也可以成功建立連接 server.ssl.client-auth=need #協(xié)議 #server.ssl.protocol=TLS #服務(wù)通信證書 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、拷貝相應(yīng)密鑰到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); //雙向校驗 校驗服務(wù)端證書是否在信任庫 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、測試代碼
服務(wù)器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()); }
服務(wù)器2(server-two)controller代碼
/** * https測試方法 * * @return */ @ApiOperation("https測試方法") @GetMapping("/httpsTest") public Result httpsTest() { log.info("服務(wù)器server-two響應(yīng)成功!"); return Result.SUCCESS(); }
服務(wù)器2(server-two)執(zhí)行結(jié)果
<200,{"code":1,"success":true,"msg":"操作成功","data":null}>
七、Nginx配置ssl證書
server { #監(jiān)聽前端訪問端口 listen 9028 ssl; #服務(wù)器地址 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; #配置服務(wù)器可使用的加密算法 ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE; # 指定服務(wù)器密碼算法在優(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)文章
將字符串數(shù)字格式化為樣式1,000,000,000的方法
這篇文章主要介紹了將字符串數(shù)字格式化為樣式1,000,000,000的方法,有需要的朋友可以參考一下2014-01-01Spring?Cloud?Alibaba微服務(wù)組件Sentinel實現(xiàn)熔斷限流
這篇文章主要為大家介紹了Spring?Cloud?Alibaba微服務(wù)組件Sentinel實現(xiàn)熔斷限流過程示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-06-06spring?jpa集成依賴的環(huán)境準備及實體類倉庫編寫教程
這篇文章主要為大家介紹了spring?jpa集成依賴的環(huán)境準備及實體類倉庫編寫教程,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-03-03JAVA通過Filter實現(xiàn)允許服務(wù)跨域請求的方法
這里的域指的是這樣的一個概念:我們認為若協(xié)議 + 域名 + 端口號均相同,那么就是同域即我們常說的瀏覽器請求的同源策略。這篇文章主要介紹了JAVA通過Filter實現(xiàn)允許服務(wù)跨域請求,需要的朋友可以參考下2018-11-11