springboot客户端与服务端实现https单向认证和双向认证

基于Spring Boot实现HTTPS方式请求下客户端与服务端进行单向认证与双向认证的实例

证书

首先准备服务端和客户端的证书。

服务端

如果是云服务器,服务端可直接由提供商生成,否则执行下面的代码生成

1、生成服务端sslServer.p12文件

1
keytool -genkey -v -alias sslServer -keyalg RSA -storetype PKCS12 -keystore E:\learning-demo\sslServer.p12

2、导出服务端公钥sslServer.cer 文件

1
keytool -keystore E:\learning-demo\sslServer.p12 -export -alias sslServer -file E:\learning-demo\sslServer.cer

在生成过程中,需要注意的一点是,第一步中“您的名字与姓氏是什么”应该填服务器的ip或对应系统的域名,这样在后面代码中校验证书就能直接通过,若填写的不一致,则需要在代码中默认允许校验自己通过。

客户端

1、生成客户端sslClient.p12文件

1
keytool -genkey -v -alias sslClient -keyalg RSA -storetype PKCS12 -keystore E:\learning-demo\sslClient.p12

2、导出客户端公钥sslClient.cer 文件

1
keytool -keystore E:\learning-demo\sslClient.p12 -export -alias sslClient -file E:\learning-demo\sslClient.cer
导入双方系统的jre运行环境的cacerts证书库

将Client端和Server端的公钥文件(.cer文件)导入双方系统的jre运行环境的cacerts证书库(双向认证需要操作此步骤)
将客户端公钥导入的服务端jdk信任库

1
keytool -import -alias sslClient -file E:\learning-demo\sslClient.cer -keystore D:\jdk\jre\lib\security\cacerts –v

将服务端公钥导入到客户端的jdk信任库

1
keytool -import -alias sslServer -file E:\learning-demo\sslServer.cer -keystore D:\jdk\jre\lib\security\cacerts –v

将客户端公钥导入到服务端Server.p12证书库

1
keytool -import -alias sslClient -v -file E:\learning-demo\sslClient.cer -keystore D:\jdk\sslServer.p12

单向认证

1
2
3
4
server.ssl.key-store=classpath:sslServer.p12
server.ssl.key-store-password=123456
server.ssl.key-alias=sslServer
server.ssl.keyStoreType=JKS

随便访问项目中的一个接口,如果页面出现下面的提示信息,则表示单向认证开启成功。

双向认证

1
2
3
4
server.ssl.trust-store-password=123456
server.ssl.client-auth=need
server.ssl.trust-store-type=JKS
server.ssl.trust-store-provider=SUN

客户端代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
private final static String TEST_URL = "https://127.0.0.1:7090/server/ssl";

@Test
public void getHKVesselTrip() throws Exception {
// 客户端证书类型
KeyStore clientStore = KeyStore.getInstance("PKCS12");
// 加载客户端证书,即自己的私钥
clientStore
.load(new FileInputStream("E:\\learning-demo\\sslClient.p12"),
"123456".toCharArray());
// 创建密钥管理工厂实例
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
// 初始化客户端密钥库
kmf.init(clientStore, "123456".toCharArray());
KeyManager[] kms = kmf.getKeyManagers();
// 创建信任库管理工厂实例
TrustManagerFactory tmf = TrustManagerFactory
.getInstance(TrustManagerFactory.getDefaultAlgorithm());
// 信任库类型
KeyStore trustStore = KeyStore.getInstance("JKS");
// 加载信任库,即服务端公钥
trustStore.load(new FileInputStream("D:\\jdk\\jre\\lib\\security\\cacerts"),
"changeit".toCharArray());
// 初始化信任库
tmf.init(trustStore);
TrustManager[] tms = tmf.getTrustManagers();
// 建立TLS连接
SSLContext sslContext = SSLContext.getInstance("TLS");
// 初始化SSLContext
sslContext.init(kms, tms, new SecureRandom());
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext,
SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
try {
HttpGet httpget = new HttpGet(TEST_URL);
System.out.println("executing request" + httpget.getRequestLine());
CloseableHttpResponse response = httpclient.execute(httpget);
try {
HttpEntity entity = response.getEntity();
if (entity != null) {
System.out.println(EntityUtils.toString(entity));
}
} finally {
response.close();
}
} finally {
httpclient.close();
}
}