是时候该写下Springboot基于Keytool的SSL双向认证代码示了
2022/3/19 6:29:58
本文主要是介绍是时候该写下Springboot基于Keytool的SSL双向认证代码示了,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
1.前言
HTTPS (全称:Hyper Text Transfer Protocol over SecureSocket Layer),是以安全为目标的 HTTP 通道,在HTTP的基础上通过传输加密和身份认证保证了传输过程的安全性 [1] 。HTTPS 在HTTP 的基础下加入SSL 层,HTTPS 的安全基础是 SSL,因此加密的详细内容就需要 SSL。 HTTPS 存在不同于 HTTP 的默认端口及一个加密/身份验证层(在 HTTP与 TCP 之间)。这个系统提供了身份验证与加密通讯方法。
JDK中keytool 常用命令: -genkey 在用户主目录中创建一个默认文件".keystore",还会产生一个mykey的别名,mykey中包含用户的公钥、私钥和证书 (在没有指定生成位置的情况下,keystore会存在用户系统默认目录,如:对于window xp系统,会生成在系统的C:/Documents and Settings/UserName/文件名为“.keystore”) -alias 产生别名 -keystore 指定密钥库的名称(产生的各类信息将不在.keystore文件中) -keyalg 指定密钥的算法 (如 RSA DSA(如果不指定默认采用DSA)) -validity 指定创建的证书有效期多少天 -keysize 指定密钥长度 -storepass 指定密钥库的密码(获取keystore信息所需的密码) -keypass 指定别名条目的密码(私钥的密码) -dname 指定证书拥有者信息 例如: "CN=名字与姓氏,OU=组织单位名称,O=组织名称,L=城市或区域名称,ST=州或省份名称,C=单位的两字母国家代码" -list 显示密钥库中的证书信息 keytool -list -v -keystore 指定keystore -storepass 密码 -v 显示密钥库中的证书详细信息 -export 将别名指定的证书导出到文件 keytool -export -alias 需要导出的别名 -keystore 指定keystore -file 指定导出的证书位置及证书名称 -storepass 密码 -file 参数指定导出到文件的文件名 -delete 删除密钥库中某条目 keytool -delete -alias 指定需删除的别 -keystore 指定keystore -storepass 密码 -printcert 查看导出的证书信息 keytool -printcert -file yushan.crt -keypasswd 修改密钥库中指定条目口令 keytool -keypasswd -alias 需修改的别名 -keypass 旧密码 -new 新密码 -storepass keystore密码 -keystore sage -storepasswd 修改keystore口令 keytool -storepasswd -keystore e:/yushan.keystore(需修改口令的keystore) -storepass 123456(原始密码) -new yushan(新密码) -import 将已签名数字证书导入密钥库 keytool -import -alias 指定导入条目的别名 -keystore 指定keystore -file 需导入的证书
本文使用okhttp3访问SpringBoot创建的https接口。
2.SpringBoot配置文件
applicathon.properties
#端口 server.port=8443 #需要分别配置Key Store和Trust Store的文件、密码等信息,即使是同一个文件。 server.ssl.enabled=true server.ssl.key-store-type=PKCS12 server.ssl.key-store=classpath:star_server.p12 server.ssl.key-store-password=xxxxxxx server.ssl.key-alias=star_server server.ssl.trust-store=classpath:star_server.p12 server.ssl.trust-store-password=xxxxxxx server.ssl.trust-store-provider=SUN server.ssl.trust-store-type=PKCS12 #server.ssl.client-auth有三个可配置的值:none、want和need。 #双向验证应该配置为need; #none表示不验证客户端; #want表示会验证,但不强制验证,即验证失败也可以成功建立连接 server.ssl.client-auth=need
3.代码逻辑
3.1 公共实体类&KeyTools工具类
KeyStoreCommand .java
public class KeyStoreCommand { private String alias;//产生别名 private int keysize;//指定密钥长度 private String keyalg; //指定密钥的算法 (如 RSA DSA(如果不指定默认采用DSA)) private String sigalg;// 签名算法名称 private String destalias; //目标别名 private String startdate;//证书有效期开始日期/时间 private String commonname;//CN=名字与姓氏 private String organizationalUnit;//OU=组织单位名称 private String organization;//O=组织名称 private String city;//L=城市或区域名称 private String state;//ST=州或省份名称 private String country;//C=单位的两字母国家代码 private long validity; //指定创建的证书有效期多少天 private String keystore;// 指定密钥库的名称 private String storepass;// 指定密钥库的密码(获取keystore信息所需的密码) private String keypass;//指定别名条目的密码(私钥的密码) private String storetype;//密钥库类型 private String filepath;// 参数指定导出到文件的证书文件名
Keytools.java类
//1.使用java代码生成密钥库 public static KeyStore createKeyStoreFile(KeyStoreCommand entity,String serverAlias,Certificate serverCert) throws Exception { final String alias = entity.getAlias();//"home2"; String keystore = entity.getKeystore();//"d:/keys/home2.p12"; final int keySize = entity.getKeysize(); //1024; final String keyalg=entity.getKeyalg();//RSA final String sigalg=entity.getSigalg();//SHA256withRSA final String commonName = entity.getCommonname();//"db"; final String organizationalUnit = entity.getOrganizationalUnit();//"com.home"; final String organization = entity.getOrganization();//"easywith"; final String city = entity.getCity();//"guiyang"; final String state = entity.getState();//"guizhou" final String country = entity.getCountry();//"cn" final long validity = entity.getValidity();//3650 final String keyPassword = entity.getKeypass();//"123456"; final String storetype = entity.getStoretype();//PKCS12 // keytool工具 CertAndKeyGen keyGen = new CertAndKeyGen(keyalg, sigalg); // 通用信息 X500Name x500Name = new X500Name(commonName, organizationalUnit, organization, city, state, country); //根据密钥长度生成公钥和私钥 keyGen.generate(keySize); PrivateKey privateKey = keyGen.getPrivateKey(); // 证书 X509Certificate certificate = keyGen.getSelfCertificate(x500Name, new Date(), (long) validity * 24 * 60 * 60); KeyStore keyStore = KeyStore.getInstance(storetype); keyStore.load(null,null); keyStore.setKeyEntry(alias,privateKey,keyPassword.toCharArray(),new Certificate[]{certificate}); System.out.println("Assigns the given trusted certificate to the given alias"); if(StringUtils.isNotEmpty(serverAlias)){ keyStore.setCertificateEntry(serverAlias,serverCert); } FileOutputStream outputStream = new FileOutputStream(keystore); keyStore.store(outputStream,keyPassword.toCharArray()); outputStream.close(); System.out.println("keyStore file created ..."); return keyStore; }
3.2 构造实体对象
3.2.1 构造KeyStoreCommand实例对象
HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat(); //拼音小写 format.setCaseType(HanyuPinyinCaseType.LOWERCASE); //不带声调 format.setToneType(HanyuPinyinToneType.WITHOUT_TONE); //要转换中文格式 String clientAlias = PinyinHelper.toHanYuPinyinString(tenant.getFullName(), format, "", true); //每次更新秘钥及证书文件版本递增(alias_0,alias_1....) clientAlias = clientAlias+"_"+tenant.getVersion(); Long validity = ((tenant.getExpaireTime().getTime() - tenant.getCreateTime().getTime()) / 86400000L); log.info("受信任证书有效天数:{}(单位:天)",validity); String CN = (tenant.getShortName()), OU = (tenant.getFullName()), O = (tenant.getShortName()), L = (PinyinHelper.toHanYuPinyinString(tenant.getCity(), format, "", true)), ST = (PinyinHelper.toHanYuPinyinString(tenant.getProvince(), format, "", true)), C = ("CN"); log.info("CN=(名字与姓氏):{}, OU=(组织单位名称):{}, O=(组织名称):{}," + " L=(城市或区域名称):{}, ST=(州或省份名称):{}, C=(单位的两字母国家代码):{}", CN,OU,O,L,ST,C); String keyStore = rootPath + clientAlias+".p12"; String cerPath = rootPath + clientAlias+".cer"; log.info("客户端秘钥库:{},受信任证书库:{}",keyStore,cerPath);
3.2.2 重点:核心操作(证书交换)双方受信任
总体步骤: 1. 创建服务端keystore秘钥库 2. 从服务端keystore秘钥库导出服务端证书 3. 创建客户端keystore秘钥库 4. 从客户端keystore秘钥库导出客户端证书 5. 将服务端证书导入客户端keystore中 6. 将客户端证书导入服务端keystore中
首先提前创建好服务端keystore并导出服务端证书(两种方式)
1.通过keytool命令行方式来创建
1.生成服务端keystore keytool -genkeypair -alias server -keyalg RSA -sigalg SHA256withRSA -dname CN="xxxxx公司",OU="易xx" ,O="大数据组" ,L=Guiyang,ST=Guizhou,C=CN -validity 3650 -keypass 123456-storepass xxxxxx -storetype PKCS12 -keystore D:/keys/starpulse_server.p12 2.导出服务端证书 keytool -export -alias server -file D:/keys/starpulse_server.cer -keystore D:/keys/starpulse_server.p12 -storetype PKCS12 -storepass 123456
2.根据java代码来创建
//1.使用java代码生成密钥库 public static KeyStore createKeyStoreFile() throws Exception { //构造KeyStoreCommand实体对象 final String alias = entity.getAlias();//"home2"; String keystore = entity.getKeystore();//"d:/keys/home2.p12"; final int keySize = entity.getKeysize(); //1024; final String keyalg=entity.getKeyalg();//RSA final String sigalg=entity.getSigalg();//SHA256withRSA final String commonName = entity.getCommonname(); final String organizationalUnit = entity.getOrganizationalUnit(); final String organization = entity.getOrganization(); final String city = entity.getCity(); final String state = entity.getState();// final String country = entity.getCountry(); final long validity = entity.getValidity(); final String keyPassword = entity.getKeypass(); final String storetype = entity.getStoretype();//PKCS12 // keytool工具 CertAndKeyGen keyGen = new CertAndKeyGen(keyalg, sigalg); // 通用信息 X500Name x500Name = new X500Name(commonName, organizationalUnit, organization, city, state, country); //根据密钥长度生成公钥和私钥 keyGen.generate(keySize); PrivateKey privateKey = keyGen.getPrivateKey(); // 证书 X509Certificate certificate = keyGen.getSelfCertificate(x500Name, new Date(), (long) validity * 24 * 60 * 60); KeyStore keyStore = KeyStore.getInstance(storetype); keyStore.load(null,null); keyStore.setKeyEntry(alias,privateKey,keyPassword.toCharArray(),new Certificate[]{certificate}); FileOutputStream outputStream = new FileOutputStream(keystore); keyStore.store(outputStream,keyPassword.toCharArray()); outputStream.close(); System.out.println("keyStore file created ..."); } //导出证书 base64格式 public static void exportCert(KeyStore keystore, String alias, String exportFile) throws Exception { Certificate cert = keystore.getCertificate(alias); BASE64Encoder encoder = new BASE64Encoder(); String encoded = encoder.encode(cert.getEncoded()); FileWriter fw = new FileWriter(exportFile); fw.write("-----BEGIN CERTIFICATE-----\r\n"); //非必须 fw.write(encoded); fw.write("\r\n-----END CERTIFICATE-----"); //非必须 fw.close(); }
核心操作(证书交换)双方受信任
//第一步:加载服务端秘钥库 KeyStore serverKeystore = KeyStore.getInstance("PKCS12"); serverKeystore.load(new FileInputStream(new File(serverStore)), password.toCharArray()); Certificate serverCert = serverKeystore.getCertificate(serverAlias); //第二步:创建客户端秘钥库(详见keytools工具类) KeyStore clientKeystore = KeyTools.createKeyStoreFile(entity,serverAlias,serverCert); KeyTools.exportCert(clientKeystore, entity.getAlias(),entity.getFilepath()); log.info("客户信任证书:{}制发完成",entity.getFilepath()); Certificate clientCert = clientKeystore.getCertificate(entity.getAlias()); log.info("根据alias导出证书客户指纹信任证书:{}",entity.getAlias()); //第三步:导入客户端证书到服务端受信库(让服务端信任客户端) serverKeystore.setCertificateEntry(entity.getAlias(),clientCert); //第四步:将服务端秘钥保存到文件 FileOutputStream outputStream = new FileOutputStream(serverStore); serverKeystore.store(outputStream,password.toCharArray()); log.info("客户:{}信任证书,alias:{}制发完成",entity.getCommonname(),entity.getAlias());
运行秘钥及证书结果如下
导出证书生成功能完成
4.示例代码使用okhttp3访问https接口
使用okhttp3访问SpringBoot创建的https接口
明天写吧,今天太累了。。。。。。。。。。。。。。。
这篇关于是时候该写下Springboot基于Keytool的SSL双向认证代码示了的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-23Springboot应用的多环境打包入门
- 2024-11-23Springboot应用的生产发布入门教程
- 2024-11-23Python编程入门指南
- 2024-11-23Java创业入门:从零开始的编程之旅
- 2024-11-23Java创业入门:新手必读的Java编程与创业指南
- 2024-11-23Java对接阿里云智能语音服务入门详解
- 2024-11-23Java对接阿里云智能语音服务入门教程
- 2024-11-23JAVA对接阿里云智能语音服务入门教程
- 2024-11-23Java副业入门:初学者的简单教程
- 2024-11-23JAVA副业入门:初学者的实战指南