JAVA使用RestTemplate类实现SSL双向/单向认证(国际)

这篇具有很好参考价值的文章主要介绍了JAVA使用RestTemplate类实现SSL双向/单向认证(国际)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

以管理员身份打开Windows PowerShel,通过cd(与linux系统类似)命令进入到JDK的bin目录:如C:\Program Files\Java\jdk1.8.0_221\jre\bin,找到目录下有keytool.exe就是正确进入目录了

生成测试用证书:

参数说明:

genkey 表示要创建一个新的密钥

alias 表示 keystore 的别名、

keyalg 表示使用的加密算法是 RSA ,一种非对称加密算法

keysize 表示密钥的长度

keystore 表示生成的密钥存放位置

validity 表示密钥的有效时间,单位为天

import 表示导入证书,如要删除导入的证书用delete即可,注意信任库主要根据别名去判断证书是否导入,别名不能重复。删除同理也通别名

1.生成TrustStore(信任库) ---证书也可以用pfx代替

keytool -genkey -alias trustkeys -storetype PKCS12 -keyalg RSA -keysize 2048 -keystore trustKeys.p12 -validity 36500

2.生成server-one客户端密钥 ---证书也可以用pfx代替

keytool -genkey -alias server-one -storetype PKCS12 -keyalg RSA -keysize 2048 -keystore server-one.p12 -validity 36500

3.生成server-two客户端密钥 ---证书也可以用pfx代替

keytool -genkey -alias server-two -storetype PKCS12 -keyalg RSA -keysize 2048 -keystore server-two.p12 -validity 36500

4.导出双方公钥

导出server-one的公钥

keytool -keystore server-one.p12 -export -alias server-one -file server-one-publicKey.cer

导出server-two的公钥

keytool -keystore server-two.p12 -export -alias server-two -file server-two-publicKey.cer

5.添加对方公钥到信任库,注意这里共用的一个信任库,所以是把两个公钥导入到一个信任库了,如果正常情况下是有两个trustKeys.p12文件,互相导入对方的公钥信息即可,如果是用CFCA的证书的话需要导入证书的二级根证书即可(公钥:一般是把二级根证书和以及根证书一起导入)

keytool -import -alias server-one -v -file server-one-publicKey.cer -keystore trustKeys.p12

keytool -import -alias server-two -v -file server-two-publicKey.cer -keystore trustKeys.p12

6.如要删除导入的信任证书

keytool -delete -alias 删除证书的别名 -keystore trustKeys.p12

搭建测试用服务端SpringBoot项目:server-one

  1. 把server-one服务的证书和信任库放到对应目录下

resttemplate 双向认证,ssl,服务器,网络协议,Powered by 金山文档
  1. 修改配置文件,开启应用SSL认证--加入下面这段配置注意配置文件格式是yml还是properties,不同文件的格式是不同的,下文是yml格式

# 开启ssl
server.ssl.enabled: true
#双向校验need
server.ssl.client-auth: need
#协议
#server.ssl.protocol: TLS
#服务通信证书
server.ssl.key-store: classpath:certFile/server-one.p12
#证书密码
server.ssl.key-store-password: 12345678
#证书格式
server.ssl.key-store-type: PKCS12
#证书别名
server.ssl.keyAlias: server-one
#信任库文件
server.ssl.trust-store: file:E:/Test_Dir/pfx/SDKtrustKeys.p12
#信任库密码
server.ssl.trust-store-password: 12345678
#信任库类型
server.ssl.trust-store-type: PKCS12
  1. 修改pom文件--在build里加入这段,在打包是把证书带入jar

<resources>
    <resource>
        <directory>src/main/java</directory>
        <includes>
            <include>**/*.xml</include>
            <include>certFile/server-one.p12</include>
            <include>certFile/trustKeys.p12</include>
        </includes>
    </resource>
    <resource>
        <directory>src/main/resources</directory>
    </resource>
</resources>
  1. 启动项目,服务端开启认证完成,通过地址去访问会发现报错--不开启认证可以访问的情况下

  1. 编写RestTemplateUtil工具类--注意提前导入Httpclient的jar包

package com.csii.gateway.util;

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.core.io.DefaultResourceLoader;
import org.springframework.core.io.ResourceLoader;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.ResponseErrorHandler;
import org.springframework.web.client.RestTemplate;

import javax.net.ssl.*;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.SecureRandom;

/**
 * @Description //HTTPS通信双向认证工具类
 * @Date 2023-02-23 11:19
 **/

//@Configuration
public class RestTemplateUtil {
    /**
     * resources 目录下证书路径
     * cerPath = "classpath:/keystore/client_trust.keystore";
     *
     *      * 根据给定的资源路径,返回响应的Resource资源对象
     *      * 支持如下三种形式:
     *      *"file:C:/test.dat".
     *      *"classpath:test.dat".
     *      *"WEB-INF/test.dat".
     *
     */
    //SDK端证书路径
    private static String clientCerPath;
   //SDK段证书密码
    private static String clientCerPwd;
    //客户端证书类型--默认PKCS12
    public static String clientCertType = "PKCS12";

    //客户端密钥库密码---就是通信证书密码
    public static String clientPass;

    //信任库路径
    public static String trustCerPath;
    //信任库密码
    public static String trustCerPass;
    //信任库证书类型--默认PKCS12
    public static String trustCertType = "PKCS12";


    public static String getClientCerPath() {
        return clientCerPath;
    }

    public static void setClientCerPath(String clientCerPath) {
        RestTemplateUtil.clientCerPath = clientCerPath;
    }

    public static String getClientCerPwd() {
        return clientCerPwd;
    }

    public static void setClientCerPwd(String clientCerPwd) {
        RestTemplateUtil.clientCerPwd = clientCerPwd;
    }

    public static String getClientPass() {
        return clientPass;
    }

    public static void setClientPass(String clientPass) {
        RestTemplateUtil.clientPass = clientPass;
    }

    public static String getTrustCerPath() {
        return trustCerPath;
    }

    public static void setTrustCerPath(String trustCerPath) {
        RestTemplateUtil.trustCerPath = trustCerPath;
    }

    public static String getTrustCerPass() {
        return trustCerPass;
    }

    public static void setTrustCerPass(String trustCerPass) {
        RestTemplateUtil.trustCerPass = trustCerPass;
    }

    public static String getClientCertType() {
        return clientCertType;
    }

    public static void setClientCertType(String clientCertType) {
        RestTemplateUtil.clientCertType = clientCertType;
    }

    public static String getTrustCertType() {
        return trustCertType;
    }

    public static void setTrustCertType(String trustCertType) {
        RestTemplateUtil.trustCertType = trustCertType;
    }


    //双向认证
    public static RestTemplate rsaSslRestTemplate() throws Exception{

        RestTemplate  restTemplate = new RestTemplate(rsaHttpComponentsClientHttpRequestFactory());
        restTemplate.setErrorHandler(new ResponseErrorHandler() {
            @Override
            public boolean hasError(ClientHttpResponse clientHttpResponse) {
                return false;
            }

            @Override
            public void handleError(ClientHttpResponse clientHttpResponse) {
                    //默认处理非200的返回,会抛异常
            }
            });

        return restTemplate;
    }

    public static CloseableHttpClient httpClient = null;

    public static HttpComponentsClientHttpRequestFactory rsaHttpComponentsClientHttpRequestFactory() throws Exception{
        //获取httpClient对象,防止重复创建--读取证书信息,对象生成后不做其他操作所以未加锁
        if(httpClient == null){
            httpClient = createCloseableHttpClientByRsa();
        }
        HttpComponentsClientHttpRequestFactory httpsFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
        httpsFactory.setReadTimeout(5000);
        httpsFactory.setConnectTimeout(5000);
        return httpsFactory;
    }

    /**
     * https协议证书认证---国际双向认证
     *
     * @return
     * @throws Exception
     */
    private static CloseableHttpClient createCloseableHttpClientByRsa() throws  Exception{

        //加载客户端证书
        KeyStore clientStore  = KeyStore.getInstance(clientCertType);
        clientStore .load(resourceLoader(clientCerPath), clientCerPwd.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(trustCertType);
        //加载信任证书
        trustStore.load(resourceLoader(trustCerPath), trustCerPass.toCharArray());
        // 初始化信任库
        trustManagerFactory.init(trustStore);

        //双向校验---校验服务端证书是否在信任库
        TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
        // 建立TLS连接
        SSLContext sslContext = SSLContext.getInstance("TLS");
        // 初始化SSLContext
        sslContext.init(keyManagers, trustManagers, new SecureRandom());

        //单项认证--不校验服务端证书是否在信任库
//        TrustStrategy anyTrustStrategy = (x509Certificates, s) -> true;
//        SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(trustStore, anyTrustStrategy).build();

        // INSTANCE 忽略域名检查
        SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE);
        //创建httpClient对象
        CloseableHttpClient closeableHttpClient = HttpClients
                .custom()
                .setSSLSocketFactory(sslConnectionSocketFactory)
                .setSSLHostnameVerifier(new NoopHostnameVerifier())
                .build();
        return closeableHttpClient;
    }

    /**
     * 读取文件信息
     *
     * @param fileFullPath
     * @return
     * @throws IOException
     */
    public static InputStream resourceLoader(String fileFullPath) throws IOException {
        ResourceLoader resourceLoader = new DefaultResourceLoader();
        return resourceLoader.getResource(fileFullPath).getInputStream();
    }
}
  1. 编辑测试方法

//客户端通信证书路径
RestTemplateUtil.setClientCerPath("file:E:/Test_Dir/pfx/server-two.p12");;
//客户端通信证书密码
RestTemplateUtil.setClientCerPwd("12345678");
//客户端密钥库密码
RestTemplateUtil.setClientPass("12345678");
//客户端信任库路径
RestTemplateUtil.setTrustCerPath("file:E:/Test_Dir/pfx/trustKeys.p12");
//客户端信任库密码
RestTemplateUtil.setTrustCerPass("12345678");
try {
//生成认证RestTemplate类,后续按正常的RestTemplate的方法去调用即可
   RestTemplate  template = RestTemplateUtil.rsaSslRestTemplate();
} catch (Exception e) {
    e.printStackTrace();
}
  1. 按上一步骤的RestTemplate去调用server-one发现可以正常访问,即双向认证完成

此文仅做记录学习参考用,如有错误还望指正

参考文章:

1.SpringBoot服务间使用自签名证书实现https双向认证 - 膜拜狂神cdy - 博客园 (cnblogs.com)

2.(2条消息) spring boot 使用RestTemplate通过证书认证访问https实现SSL请求_踩到最基点的博客-CSDN博客文章来源地址https://www.toymoban.com/news/detail-616845.html

到了这里,关于JAVA使用RestTemplate类实现SSL双向/单向认证(国际)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • c++使用OpenSSL基于socket实现tcp双向认证ssl(使用TSL协议)代码实现

    相信各位对OpenSSL库已经不陌生了,目前笔者使用这个库实现了RSA、AES加解密和tcp的双向认证功能,下面来看tcp的双向认证。 简单说双向认证就是:客户端认证服务端是否合法,服务端认证客户端是否合法 。 可以借助于HTTPS来说明,http网络传输协议是超文本的明文协议,也就

    2024年02月06日
    浏览(55)
  • HTTPS单向认证与双向认证

    Https就是HTTP+SSL/TSL的简称。 SSL(Secure Socket Layer 安全套接层)是TCP/IP协议中基于HTTP之下TCP之上的一个可选协议层。 起初HTTP在传输数据时使用的是明文,传输过程中并不安全。网景(Netscap)公司推出了SSL解决了这一安全隐患,因此越来越多的人也开始使用HTTPS。在SSL更新到3.0时,

    2024年02月11日
    浏览(39)
  • 【网络】https单向认证和双向认证

    之前面试的时候,面试官问我了解过https的双向认证吗?当时,的确不理解。不过没关系,现在就来补上。 1.单向认证 还是有必要先说下单向认证,单向认证是我刚开始接触https的时候就了解到的。下面看一下执行流程图 (图是网上找的) 再用文字描述下: 首先建立链接  - 验

    2023年04月09日
    浏览(49)
  • ssl单向证书和双向证书校验测试及搭建流程

    首先了解下HTTP和HTTPS的区别: HTTPS与HTTP有什么不同? HTTP是过去很长一段时间我们经常用到的一种传输协议。HTTP协议传输的数据都是未加密的,这就意味着用户填写的密码、账号、交易记录等机密信息都是明文,随时可能被泄露、窃取、篡改,从而被黑客加以利用,因此使用

    2024年02月13日
    浏览(32)
  • 【算法】Java-使用数组模拟单向链表,双向链表

    目录 试题1:实现一个单链表,并实现以下功能: 试题2:实现一个双链表,并实现以下功能 思路总结: 什么情况下可能涉及到用数组实现链表呢?       在学习时了解到了可以用数组模拟链表,使其兼顾数据查找快,链表新增和删除快的缺点,找来一些试题实现了下,如下

    2024年02月09日
    浏览(46)
  • 双向SSL认证证书 生成 jks 步骤, java用jks 发送http请求 方法

    ) 1.证书的 cert.pem 文件 2.key文件 3.key的密钥 这里只显示 liunx 命令 ,windows 的同学可自查 这个命令会提示输入3次密码 ,第一次输入xxx.key的密码 , 第二次提示输入导出密码 自己设就行 ,这里用 changeit 注意: 第一次 不是自己设的 需要用 key文件的密钥 这里会用 上一步骤的导

    2024年02月06日
    浏览(40)
  • springboot项目开启ssl双向认证且实现相互访问通信浏览器访问通信

    1、服务器端===生成自签名证书** 这段命令是使用Java的keytool工具生成一个RSA算法的密钥对,并将其保存在名为server.jks的密钥库文件中。以下是各个参数的解释: -genkeypair:生成密钥对的命令。 -keyalg RSA:指定使用RSA算法生成密钥对。 -keysize 2048:指定生成的密钥长度为2048位。

    2024年03月21日
    浏览(42)
  • 【数据结构和算法】使用数组的结构实现链表(单向或双向)

    上文我们通过结构体的结构实现了队列 、以及循环队列的实现,我们或许在其他老师的教学中,只学到了用结构体的形式来实现链表、队列、栈等数据结构,本文我想告诉你的是,我们 可以使用数组的结构实现链表、单调栈、单调队列 目录 前言 一、用数组结构的好处 1.数

    2024年01月20日
    浏览(70)
  • SpringBoot整合自签名SSL证书,转变HTTPS安全访问(单向认证服务端)

    HTTP 具有相当优秀和方便的一面,然而 HTTP 并非只有好的一面,事物皆具两面性,它也是有不足之处的。例如: 通信使用明文(不加密),内容可能会被窃听。 不验证通信方的身份,因此有可能会遭遇伪装。 无法证明报文的完整性,所以有可能会遭篡改等。 因HTTP有存在通信

    2024年02月06日
    浏览(59)
  • 使用RestTemplate访问https实现SSL请求操作,设置TLS版本

    注意:服务端TLS版本要和客户端工具类中定义的一致, 当支持的是列表时,能够与不同版本的客户端进行通信,在握手期间,TLS会选择两者都支持的最高的版本 javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure解决方案 方法升级JDK版本 全局设置优先级 代码里面的设置

    2024年02月01日
    浏览(38)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包