当前位置: 代码迷 >> 综合 >> https单向认证和双向认证demo(SpringBoot+okhttp3+keytool自签名)
  详细解决方案

https单向认证和双向认证demo(SpringBoot+okhttp3+keytool自签名)

热度:6   发布时间:2024-02-12 20:22:22.0

目录

 

一、前言

二、软件版本

三、单向认证

四、双向认证


一、前言

HTTPS (全称:Hyper Text Transfer Protocol over SecureSocket Layer),是以安全为目标的 HTTP 通道,在HTTP的基础上通过传输加密和身份认证保证了传输过程的安全性 [1]  。HTTPS 在HTTP 的基础下加入SSL 层,HTTPS 的安全基础是 SSL,因此加密的详细内容就需要 SSL。 HTTPS 存在不同于 HTTP 的默认端口及一个加密/身份验证层(在 HTTP与 TCP 之间)。这个系统提供了身份验证与加密通讯方法。

本文使用okhttp3访问SpringBoot创建的https接口。

二、软件版本

SpringBoot:2.1.2

okhttp3:3.2.0

keytool:jdk1.8.0_77

三、单向认证

1生成服务端证书

keytool -genkey -alias server -keypass 123456 -keyalg RSA -keysize 1024 -validity 365 -storepass 123456 -storetype PKCS12 -keystore C:\Users\admin\Desktop\server.p12

记住秘钥库口令,在SpringBoot配置中使用

2导出服务端cer证书

keytool -export -alias server -keystore C:\Users\admin\Desktop\server.p12 -storetype PKCS12 -keypass 123456 -file C:\Users\admin\Desktop\server.cer

3配置SpringBoot

将server.p12拷贝到SpringBoot的resources目录

#ssl配置
server.ssl.enabled=true
server.ssl.key-store=classpath:server.p12
server.ssl.key-store-password=123456
server.ssl.key-store-type=JKS
# 证书别名
server.ssl.key-alias=server
4浏览器测试

访问https://localhost:8080/demo

5okhttp3测试

path:者指定server.cer的路径

package com.asyf.demo.other_api.okhttp3;import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;import javax.net.ssl.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.SecureRandom;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;/*** https单向认证*/
public class Test2 {//安全传输层协议private static final String PROTOCOL = "TLS";// JKS/PKCS12private static final String KEY_KEYSTORE_TYPE = "PKCS12";private static SSLSocketFactory getSocketFactory(String cerPath) throws Exception {SSLSocketFactory socketFactory = null;try (InputStream cerInputStream = new FileInputStream(new File(cerPath))) {TrustManager[] trustManagers = getTrustManagers(cerInputStream);SSLContext sslContext = getSslContext(trustManagers);socketFactory = sslContext.getSocketFactory();}return socketFactory;}private static SSLContext getSslContext(TrustManager[] trustManagers) throws Exception {SSLContext sslContext = SSLContext.getInstance(PROTOCOL);sslContext.init(null, trustManagers, new SecureRandom());return sslContext;}private static TrustManager[] getTrustManagers(InputStream inputStream) throws Exception {TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());KeyStore keyStore = KeyStore.getInstance(KEY_KEYSTORE_TYPE);//加载证书CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");Certificate ca = certificateFactory.generateCertificate(inputStream);keyStore.load(null, null);//设置公钥keyStore.setCertificateEntry("server", ca);trustManagerFactory.init(keyStore);TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();return trustManagers;}public static void main(String[] args) throws Exception {//获取SSLSocketFactoryString certPath = "D:\\workspace\\asyf_demo\\demo\\src\\main\\java\\com\\asyf\\demo\\other_api\\okhttp3\\server.cer";//服务端公钥SSLSocketFactory socketFactory = getSocketFactory(certPath);//发送请求String url = "https://127.0.0.1:8080/demo";OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder();clientBuilder.sslSocketFactory(socketFactory);//解决报错javax.net.ssl.SSLPeerUnverifiedException: Hostname 127.0.0.1 not verifiedclientBuilder.hostnameVerifier(new HostnameVerifier() {@Overridepublic boolean verify(String s, SSLSession sslSession) {System.out.println("主机:" + s);return true;}});OkHttpClient client = clientBuilder.build();Request.Builder builder = new Request.Builder().url(url);Request request = builder.build();Response response = client.newCall(request).execute();String result = response.body().string();//打印请求结果System.out.println(result);}}

 控制台:

四、双向认证

1生成客户端证书

keytool -genkey -alias client -keypass 123456 -keyalg RSA -keysize 1024 -validity 365 -storepass 123456 -storetype PKCS12 -keystore C:\Users\admin\Desktop\client.p12

2导出客户端cer证书

keytool -export -alias client -keystore C:\Users\admin\Desktop\client.p12 -storetype PKCS12 -keypass 123456 -file C:\Users\admin\Desktop\client.cer

3生成keystore用来存储springboot信任的证书

keytool -genkey -alias springboot_keystore -keypass 123456 -keyalg RSA -keysize 1024 -validity 365 -storepass 123456 -storetype PKCS12 -keystore C:\Users\admin\Desktop\springboot_keystore.keystore

4导入客户端的公钥到springboot_keystore.keystore

keytool -import -v -file C:\Users\admin\Desktop\client.cer -keystore C:\Users\admin\Desktop\springboot_keystore.keystore -storepass 123456

5配置SpringBoot

将springboot_keystore.keystore拷贝到SpringBoot项目,并添加如下配置

#双向认证配置
server.ssl.trust-store=classpath:springboot_keystore.keystore
server.ssl.trust-store-password=123456
server.ssl.client-auth=need
server.ssl.trust-store-type=JKS
server.ssl.trust-store-provider=SUN
6浏览器测试

直接访问会出现如下错误

需要在电脑中安装证书

双击client.p12,安装证书(demo是win10环境)

安装成功后刷新浏览器,提示选择证书。点击“确定”。

然后访问https接口,看到如下图的结果,说明配置成功。

7okhttp3测试

path:指定client.p12的路径

如果使用单向认证的main函数继续访问,控制台打印异常信息:

Exception in thread "main" javax.net.ssl.SSLHandshakeException: Received fatal alert: bad_certificate

测试代码:


 
package com.asyf.demo.other_api.okhttp3;import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;import javax.net.ssl.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.SecureRandom;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;/*** https双向认证*/
public class Test {//安全传输层协议private static final String PROTOCOL = "TLS";// JKS/PKCS12private static final String KEY_KEYSTORE_TYPE = "PKCS12";public static SSLSocketFactory getSocketFactory(String cerPath, String p12Path, String password) throws Exception {InputStream cerInputStream = null;InputStream p12InputStream = null;SSLSocketFactory socketFactory = null;try {cerInputStream = new FileInputStream(new File(cerPath));p12InputStream = new FileInputStream(new File(p12Path));KeyManager[] keyManagers = getKeyManagers(p12InputStream, password);TrustManager[] trustManagers = getTrustManagers(cerInputStream);SSLContext sslContext = getSslContext(keyManagers, trustManagers);socketFactory = sslContext.getSocketFactory();} finally {if (cerInputStream != null) {cerInputStream.close();}if (p12InputStream != null) {p12InputStream.close();}}return socketFactory;}private static SSLContext getSslContext(KeyManager[] keyManagers, TrustManager[] trustManagers) throws Exception {SSLContext sslContext = SSLContext.getInstance(PROTOCOL);sslContext.init(keyManagers, trustManagers, new SecureRandom());return sslContext;}private static KeyManager[] getKeyManagers(InputStream inputStream, String password) throws Exception {KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());KeyStore keyStore = KeyStore.getInstance(KEY_KEYSTORE_TYPE);//加载证书keyStore.load(inputStream, password.toCharArray());keyManagerFactory.init(keyStore, password.toCharArray());KeyManager[] keyManagers = keyManagerFactory.getKeyManagers();return keyManagers;}private static TrustManager[] getTrustManagers(InputStream inputStream) throws Exception {TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());KeyStore keyStore = KeyStore.getInstance(KEY_KEYSTORE_TYPE);//加载证书CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");Certificate ca = certificateFactory.generateCertificate(inputStream);keyStore.load(null, null);//设置公钥keyStore.setCertificateEntry("server", ca);trustManagerFactory.init(keyStore);TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();return trustManagers;}public static void main(String[] args) throws Exception {//获取SSLSocketFactoryString certPath = "D:\\workspace\\asyf_demo\\demo\\src\\main\\java\\com\\asyf\\demo\\other_api\\okhttp3\\server.cer";//服务端公钥String p12Path = "D:\\workspace\\asyf_demo\\demo\\src\\main\\java\\com\\asyf\\demo\\other_api\\okhttp3\\client.p12";//客户端私钥SSLSocketFactory socketFactory = getSocketFactory(certPath, p12Path, "123456");//发送请求String url = "https://127.0.0.1:8080/demo";OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder();clientBuilder.sslSocketFactory(socketFactory);//解决报错javax.net.ssl.SSLPeerUnverifiedException: Hostname 127.0.0.1 not verifiedclientBuilder.hostnameVerifier(new HostnameVerifier() {@Overridepublic boolean verify(String s, SSLSession sslSession) {System.out.println("主机:" + s);return true;}});OkHttpClient client = clientBuilder.build();Request.Builder builder = new Request.Builder().url(url);Request request = builder.build();Response response = client.newCall(request).execute();String result = response.body().string();//打印结果返回数据System.out.println(result);}}

控制台:

  相关解决方案