springboot通过已有的server.key,crt,ca证书生成jks文件并开启HTTPS 并启动双向认证+动态加载信任库
Springboot开启双向验证
yaml文件配置
证书生成
热加载信任库
测试
yaml文件配置
server:
port: 6820
ssl:
enabled: true
key-store: C:\Users\Administrator\Desktop\server.jks ## 这里放到桌面,原因后面会说
key-store-password: changeit
key-alias: localhost
key-store-type: JKS
trust-store: C:\Users\Administrator\Desktop\server.jks
trust-store-password: changeit ## 密码最好用这个
trust-store-provider: SUN
trust-store-typ: JKS
client-auth: need ## 开启双向认证的必要条件
证书生成
1.通过服务端crt和key生成p12格式证书
openssl pkcs12 -export -in server.crt -inkey server.key -out server.p12 -name localhost -CAfile ca.crt -caname root
2.p12格式转为jks格式
keytool -importkeystore -destkeystore server.jks -srckeystore server.p12 -srcstoretype pkcs12 -alias localhost
3.客户端证书导入服务端
keytool -import -alias client -file client.crt -keystore server.jks -storepass changeit -trustcacerts
4.通过客户端crt和key生成p12格式证书
openssl pkcs12 -export -in client.crt -inkey client.key -out client.p12 -name localhost -CAfile ca.crt -caname root
5.将服务端证书导入客户端
keytool -importcert -keystore client.p12 -alias servercert -file server.crt
--------以下为验证部分
检验服务端是否具有自己的private key和客户端的cert
keytool -list -keystore server.jks
验证证书是否合法
CERTUTIL -urlfetch -verify client.crt
热加载信任库
服务端的jks文件不要放在resource文件下,网上很多博文都是放到这个目录,其实根本不能进行热加载,因为打包之后 是不能对resource文件夹下的文件进行修改替换的,必须放到jar包外层。
配置Tomcat,使得TrustManagerClassName可被设置,代码如下:
@Configuration
@ConditionalOnClass({Servlet.class, Tomcat.class, UpgradeProtocol.class})
public class SslTomcatAutoConfiguration {
@Autowired
private X509TrustManager x509TrustManager;
@Bean
public SslWebServerFactoryCustomizer hotSslWebServerFactoryCustomizer() {
return new SslWebServerFactoryCustomizer(x509TrustManager);
}
@Bean
@ConditionalOnMissingBean
public X509TrustManager x509TrustManager() {
return new SslX509TrustManager();
}
}
使用自定义{ProtocolHandler},主要是为了设置{@link AbstractHttp11Protocol#setTrustManagerClassName(String)}}
public class HttpsNioProtocol extends Http11NioProtocol {
public HttpsNioProtocol() {
super.setTrustManagerClassName(SslWebServerFactoryCustomizer.SslTrustManager.class.getName());
}
}
SslWebServerFactoryCustomizer
public class SslWebServerFactoryCustomizer implements WebServerFactoryCustomizer<TomcatServletWebServerFactory> {
private static X509TrustManager x509TrustManager;
public SslWebServerFactoryCustomizer(X509TrustManager x509TrustManager) {
SslWebServerFactoryCustomizer.x509TrustManager = x509TrustManager;
}
@Override
public void customize(TomcatServletWebServerFactory factory) {
factory.setProtocol(HttpsNioProtocol.class.getName());
}
/**
* 热加载受信证书管理器
*/
public static class SslTrustManager implements X509TrustManager {
@Override
public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
x509TrustManager.checkClientTrusted(x509Certificates, s);
}
@Override
public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
x509TrustManager.checkServerTrusted(x509Certificates, s);
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return x509TrustManager.getAcceptedIssuers();
}
}
}
SslX509TrustManager
public class SslX509TrustManager implements X509TrustManager {
@Value("${server.ssl.trust-store}")
private String trustStore;
@Value("${server.ssl.trust-store-password}")
private String trustStorePassword = "";
@Value("${server.ssl.trust-store-type:JKS}")
private String trustStoreType;
/**
* @param x509Certificates 客户端传过来的证书
* @param s 加密方式
* @throws CertificateException
*/
@Override
public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
KeyStore keyStore = KeyStoreLoader.load(trustStore, trustStorePassword, trustStoreType);
if (ObjectUtils.isEmpty(keyStore)) {
System.out.println("验证不通过");
throw new CertificateException();
}
for (X509Certificate x509Certificate : x509Certificates) {
try {
if (keyStore.getCertificateAlias(x509Certificate) != null) {
System.out.println("验证通过");
return;
}
} catch (Exception e) {
// pass
}
}
System.out.println("验证不通过");
try {
storeTrust();
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
throw new CertificateException();
}
@Override
public void checkServerTrusted(X509Certificate[] x509Certificates, String s) {
// 一般不用管,验证服务端的证书是否都有效
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
}
KeyStore加载器,主要完成从文件加载
public class KeyStoreLoader {
private KeyStoreLoader() {
}
private static ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
public static KeyStore load(String name, String password, String type) {
File file = new File(name);
KeyStore keyStore;
try {
InputStream inputStream = new FileInputStream(file);
try {
keyStore = KeyStore.getInstance(type);
keyStore.load(inputStream, password.toCharArray());
return keyStore;
} catch (Exception e) {
throw new RuntimeException(e);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return null;
}
}
将以上代码配置好之后就不要其他操作拉。
测试
自定义接口
@RestController
@RequestMapping("/test")
public class TestController {
@GetMapping("/test")
public String test(){
return "777";
}
}
首先未在server.jks中导入客户端证书,访问接口:
访问失败了。
通过keytool命令加入客户端证书,在进行访问:
访问成功。
如果要测试删除证书是否能访问,需要重启浏览器哦。
————————————————
版权声明:本文为CSDN博主「别卷了啊」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_34239851/article/details/121371896