【HTTPS】Spring Boot客户端与服务端单向认证和双向认证实例

2024-08-25 18:32

本文主要是介绍【HTTPS】Spring Boot客户端与服务端单向认证和双向认证实例,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

【引言】

在上篇博客中,了解了关于SSL的很多理论,本篇博客主要是总结下基于Spring Boot实现HTTPS方式请求下客户端与服务端进行单向认证与双向认证的实例搭建。

有了上一篇博客的认识,对于SSL的流程已经很清楚了。使用HTTPS,通常情况下,是客户端需要校验服务端,也就是一个单向认证的过程。同时,服务端也可以校验客户端,从而达到客户端与服务端双向认证的目的。

【证书生成】

在项目搭建前,我们先使用JDK下的KeyTool工具生成服务端证书和客户端证书,在后面的代码中需要用到。下面是生成证书步骤,在JDK安装目录下的JRE目录下的bin文件夹下执行命令即可:

  • Server端证书生成步骤
  1. 生成服务端sslServer.p12文件
    keytool -genkey -v -alias sslServer -keyalg RSA -storetype PKCS12 -keystore E:\learning-demo\sslServer.p12

  2. 导出服务端公钥sslServer.cer 文件
    keytool -keystore E:\learning-demo\sslServer.p12 -export -alias sslServer -file E:\learning-demo\sslServer.cer

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

按照以上方法,同样,生成客户端证书:

  • Client端证书生成步骤(双向认证需要操作此步骤)
  1. 生成客户端sslClient.p12文件
    keytool -genkey -v -alias sslClient -keyalg RSA -storetype PKCS12 -keystore E:\learning-demo\sslClient.p12

  2. 导出客户端公钥sslClient.cer 文件
    keytool -keystore E:\learning-demo\sslClient.p12 -export -alias sslClient -file E:\learning-demo\sslClient.cer

  • 将Client端和Server端的公钥文件(.cer文件)导入双方系统的jre运行环境的cacerts证书库(双向认证需要操作此步骤)
  1. 将客户端公钥导入的服务端jdk信任库
    keytool -import -alias sslClient -file E:\learning-demo\sslClient.cer -keystore D:\jdk\jre\lib\security\cacerts –v

  2. 将服务端公钥导入到客户端的jdk信任库
    keytool -import -alias sslServer -file E:\learning-demo\sslServer.cer -keystore D:\jdk\jre\lib\security\cacerts –v

  3. 将客户端公钥导入到服务端Server.p12证书库
    keytool -import -alias sslClient -v -file E:\learning-demo\sslClient.cer -keystore D:\jdk\sslServer.p12

【实例搭建】

新建springboot-https项目,包含springboot-https-server(服务端)和springboot-https-client(客户端)两个模块。

  • 单向认证

搭建好springboot-https-server模块后,在application.properties配置文件下,添加以下内容,则可在服务端开启SSL认证,证书放在resource目录下即可:

# 单向认证开启(客户端校验服务端证书即可)
server.port=7090
server.address=127.0.0.1
server.ssl.key-store=classpath:sslServer.p12
server.ssl.key-store-password=123456
server.ssl.key-alias=sslServer
server.ssl.keyStoreType=JKS

对外提供一个接口,测试是否开启成功:

@RestController
@RequestMapping("/server")
public class ServerController {@RequestMapping("/ssl")public String getUrlInfo() {return "************request https success************";}}

我们在浏览器直接访问https://127.0.0.1:7090/server/ssl这一接口,浏览器会提示:
在这里插入图片描述
则表明单向认证开启成功。

  • 双向认证

双向认证,首先需要在服务端中加以下配置,表示服务端需要校验客户端:

# 开启双向认证(客户端与服务端互相校验)
server.ssl.trust-store-password=123456
server.ssl.client-auth=need
server.ssl.trust-store-type=JKS
server.ssl.trust-store-provider=SUN

客户端测试代码:

  private final static String TEST_URL = "https://127.0.0.1:7090/server/ssl";@Testpublic 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");// 初始化SSLContextsslContext.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();}}

仔细读代码,会发现也就是上篇博客中核心类的内容,如何建立SSLContext连接,其中KeyStore和TrustStore如何创建,都有涉及。

项目实例代码已上传github,地址:https://github.com/huzhiting/springboot-https

【总结】

在进行双向认证的过程中,很容易出现校验不通过的情况,还是需要具体问题具体分析。

HTTPClient方式调用尝试很多次不能校验通过的情况下,可以换成HTTPURLConnection试试,毕竟HttpURLConnection是java的标准类。

这篇关于【HTTPS】Spring Boot客户端与服务端单向认证和双向认证实例的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1106328

相关文章

Java中流式并行操作parallelStream的原理和使用方法

《Java中流式并行操作parallelStream的原理和使用方法》本文详细介绍了Java中的并行流(parallelStream)的原理、正确使用方法以及在实际业务中的应用案例,并指出在使用并行流... 目录Java中流式并行操作parallelStream0. 问题的产生1. 什么是parallelS

Java中Redisson 的原理深度解析

《Java中Redisson的原理深度解析》Redisson是一个高性能的Redis客户端,它通过将Redis数据结构映射为Java对象和分布式对象,实现了在Java应用中方便地使用Redis,本文... 目录前言一、核心设计理念二、核心架构与通信层1. 基于 Netty 的异步非阻塞通信2. 编解码器三、

SpringBoot基于注解实现数据库字段回填的完整方案

《SpringBoot基于注解实现数据库字段回填的完整方案》这篇文章主要为大家详细介绍了SpringBoot如何基于注解实现数据库字段回填的相关方法,文中的示例代码讲解详细,感兴趣的小伙伴可以了解... 目录数据库表pom.XMLRelationFieldRelationFieldMapping基础的一些代

一篇文章彻底搞懂macOS如何决定java环境

《一篇文章彻底搞懂macOS如何决定java环境》MacOS作为一个功能强大的操作系统,为开发者提供了丰富的开发工具和框架,下面:本文主要介绍macOS如何决定java环境的相关资料,文中通过代码... 目录方法一:使用 which命令方法二:使用 Java_home工具(Apple 官方推荐)那问题来了,

Java HashMap的底层实现原理深度解析

《JavaHashMap的底层实现原理深度解析》HashMap基于数组+链表+红黑树结构,通过哈希算法和扩容机制优化性能,负载因子与树化阈值平衡效率,是Java开发必备的高效数据结构,本文给大家介绍... 目录一、概述:HashMap的宏观结构二、核心数据结构解析1. 数组(桶数组)2. 链表节点(Node

Java AOP面向切面编程的概念和实现方式

《JavaAOP面向切面编程的概念和实现方式》AOP是面向切面编程,通过动态代理将横切关注点(如日志、事务)与核心业务逻辑分离,提升代码复用性和可维护性,本文给大家介绍JavaAOP面向切面编程的概... 目录一、AOP 是什么?二、AOP 的核心概念与实现方式核心概念实现方式三、Spring AOP 的关

详解SpringBoot+Ehcache使用示例

《详解SpringBoot+Ehcache使用示例》本文介绍了SpringBoot中配置Ehcache、自定义get/set方式,并实际使用缓存的过程,文中通过示例代码介绍的非常详细,对大家的学习或者... 目录摘要概念内存与磁盘持久化存储:配置灵活性:编码示例引入依赖:配置ehcache.XML文件:配置

Java 虚拟线程的创建与使用深度解析

《Java虚拟线程的创建与使用深度解析》虚拟线程是Java19中以预览特性形式引入,Java21起正式发布的轻量级线程,本文给大家介绍Java虚拟线程的创建与使用,感兴趣的朋友一起看看吧... 目录一、虚拟线程简介1.1 什么是虚拟线程?1.2 为什么需要虚拟线程?二、虚拟线程与平台线程对比代码对比示例:三

Java中的.close()举例详解

《Java中的.close()举例详解》.close()方法只适用于通过window.open()打开的弹出窗口,对于浏览器的主窗口,如果没有得到用户允许是不能关闭的,:本文主要介绍Java中的.... 目录当你遇到以下三种情况时,一定要记得使用 .close():用法作用举例如何判断代码中的 input

Spring Gateway动态路由实现方案

《SpringGateway动态路由实现方案》本文主要介绍了SpringGateway动态路由实现方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随... 目录前沿何为路由RouteDefinitionRouteLocator工作流程动态路由实现尾巴前沿S