springboot整合https实现双向认证

一、生成自签名根证书
1.创建根证书私钥:

openssl genrsa -out root.key 1024


2.创建根证书请求文件:

openssl req -new -out root.csr -key root.key


3.创建根证书:

openssl x509 -req -in root.csr -out root.crt -signkey root.key -CAcreateserial -days 3650

这个步骤会生成3个文件:
root.key
root.csr
root.crt

字段解读
C字段:Country,单位所在国家,为两位数的国家缩写,如:CN 表示中国;
ST 字段:State/Province,单位所在州或省;
L 字段:Locality,单位所在城市/或县区;
O 字段:Organization,此网站的单位名称;
OU 字段:Organization Unit,下属部门名称,也常常用于显示其他证书相关信息,如证书类型,证书产品名称或身份验证类型或验证内容等;
CN 字段:Common Name,网站的域名;

二、生成自签名服务器端证书
1.生成服务器端证书私钥:

openssl genrsa -out server.key 1024


2.生成服务器证书请求文件

openssl req -new -out server.csr -key server.key


3.生成服务器端公钥证书
--v1版本

openssl x509 -req -in server.csr -out server.crt -signkey server.key -CA root.crt -CAkey root.key -CAcreateserial -days 3650


--v3版本

openssl x509 -req -days 3650 -in server.csr -CA root.crt -CAkey root.key -CAcreateserial -out server.crt -extensions v3_req -extensions v3_ca -extfile /usr/local/ssl/openssl.conf


-extensions v3_req 指定 X.509 v3版本
-extensions v3_ca 生成CA扩展名
-extfile ./openssl.conf 指定特殊的配置文件


这个步骤会生成这2个文件:
server.key:服务器端的秘钥文件
server.crt:有效期十年的服务器端公钥证书,使用根证书和服务器端私钥文件一起生成(这个要发给对方)

三.转Java可用格式
1.转换为pkcs12格式(因为在Java中使用证书,需要转换一下格式)

openssl pkcs12 -export -clcerts -in server.crt -inkey server.key -out server.p12


或者

openssl pkcs12 -export -clcerts -in server.crt -inkey server.key -out server.pkcs12

2.pkcs12格式转JKS格式

keytool -importkeystore -srckeystore server.p12 -srcstoretype PKCS12 -deststoretype JKS -destkeystore server.jks


四、导入对方公钥证书(.crt)到密钥库

keytool -import -alias clcert -file clcert.crt -keystore server.jks


查看密钥库命令:

keytool -list -v -keystore server.jks

五、配置Spirngboot
1.把.jks文件放到resources目录下


server:
  port: 5577
  ssl:
    enabled: true
    key-store: classpath:server.jks
    key-store-type: JKS
    key-store-password: changeit

    trust-store: classpath:server.jks
    trust-store-password: changeit
    trust-store-type: JKS
    client-auth: need
    

https双向认证建立连接的过程:

客户端向服务端发送SSL协议版本号、加密算法种类、随机数等信息;

服务端给客户端返回SSL协议版本号、加密算法种类、随机数等信息,同时也返回服务器端的证书,即公钥证书;

客户端使用服务端返回的信息验证服务器端的合法性,包括:

(1)证书是否过期
(2)颁发服务器证书的CA是否可靠
(3)返回的公钥是否能正确解开返回证书中的数字签名
(4)服务器证书上的域名是否和服务器的实际域名相匹配
验证通过后,将继续进行通信,否则,终止通信;

服务端要求客户端发送客户端的证书,客户端会将自己的证书发送至服务端;

验证客户端的证书,通过验证后,会获得客户端的公钥;

客户端向服务端发送自己所能支持的对称加密方案,供服务器端进行选择;

服务器端在客户端提供的加密方案中选择加密程度最高的加密方式;

将加密方案通过使用之前获取到的公钥进行加密,返回给客户端;

客户端收到服务端返回的加密方案密文后,使用自己的私钥进行解密,获取具体加密方式,而后,产生该加密方式的随机码,用作加密过程中的密钥,使用之前从服务端证书中获取到的公钥进行加密后,发送给服务端;

服务端收到客户端发送的消息后,使用自己的私钥进行解密,获取对称加密的密钥,在接下来的会话中,服务器和客户端将会使用该密码进行对称加密,保证通信过程中信息的安全。    
    

java调用https工具类




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;


@Configuration
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());
            // 创建密钥管理工厂实例
            KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
            // 初始化客户端密钥库
            keyManagerFactory.init(clientStore, clientPass.toCharArray());
            KeyManager[] keyManagers = keyManagerFactory.getKeyManagers();

            // 创建信任库管理工厂实例
            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);
            //SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext);
            CloseableHttpClient httpclient = HttpClients
                    .custom()
                    .setSSLSocketFactory(sslConnectionSocketFactory)
                    .setSSLHostnameVerifier(new NoopHostnameVerifier())
                    .build();
            requestFactory.setHttpClient(httpclient);
            requestFactory.setConnectTimeout((int) Duration.ofSeconds(30).toMillis());
            restTemplate = new RestTemplate(requestFactory);
        } catch (KeyManagementException | FileNotFoundException | NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (KeyStoreException | CertificateException | UnrecoverableKeyException | IOException e) {
            e.printStackTrace();
        }
        return restTemplate;
    }
}

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值