Spring Boot 实现https ssl免密登录(X.509 pki登录)
作者:Shurlormes 发布时间:2023-07-28 18:46:11
要让项目实现 ssl 免密登录,首先需要开启 https 。
所以先从 Spring Boot 如何开启 https 说起。
创建服务端证书
为了开启 https ,我们需要一份证书。
实际开发中,会在网上申请一个机构颁发的证书。这里为了方便,我会使用 openssl 命令自己生成一个证书来使用。
openssl req -x509 -sha256 -days 3650 -newkey rsa:4096 -keyout rootCA.key -out rootCA.crt
所有的密码都是 123456 ,然后根据提示输入相关信息就好,如果嫌麻烦也可以直接回车跳过。
这样我们就得到了证书 rootCA.crt 和私钥 rootCA.key 。
要在 Spring Boot 中实现服务器端 X.509 身份验证,还需要给我们的服务端也生成一个证书。
openssl req -new -newkey rsa:4096 -keyout localhost.key -out localhost.csr
同样,密码是 123456 ,文件名 localhost 可以自行修改。
接下来就是用 rootCA 给我们的服务端证书做签名了,在此之前,我们先写一个配置文件,里面写有一些基本的配置
vi conf.config
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
subjectAltName = @alt_names
[alt_names]
DNS.1 = localhost
其中 DNS.1 的值就是你的域名,比如 www.segmentfault.com , localhost 等等。如果这里填错了,访问网站时,浏览器会提示网站不安全。
然后给服务端证书签名,会提示你输入 rootCA 的密码
openssl x509 -req -CA rootCA.crt -CAkey rootCA.key -in localhost.csr -out localhost.crt -days 365 -CAcreateserial -extfile conf.config
成功后,让我们查看一下证书的信息
openssl x509 -in localhost.crt -text
最后再将签名证书和私钥打包到 PKCS 文件中
openssl pkcs12 -export -out localhost.p12 -name "localhost" -inkey localhost.key -in localhost.crt
这条指令会要你先输入 localhost.key 的密码,然后再要你定义 localhost.p12 的密码。 localhost.p12 这个密码一定要记住,因为在 Spring 的配置文件中有用到。
另外需要特别注意的是, Spring 配置文件中 server.ssl.keyAlias 的值,就是命令中的 localhost(-name "localhost") 。
Spring Boot开启https
把 localhost.p12 复制到 resources 目录下之后编译项目
修改application.properties文件
server.port=8888
server.ssl.key-store=classpath:localhost.p12
server.ssl.key-store-password=123456
server.ssl.keyStoreType=PKCS12
server.ssl.keyAlias=localhost
在 chrome://settings/security 中,选择 受信任的根证书颁发机构 导入 rootCA.crt
这时启动项目,就可以使用 https 访问网站了,而且浏览器提示网站时安全的。
创建信托证书
信托证书中会存有 信任的外部实体的证书
这里我们只要将 rootCA.crt 添加进去就可以了
keytool -import -trustcacerts -noprompt -alias ca -ext san=dns:localhost,ip:127.0.0.1 -file rootCA.crt -keystore localhost.jks
然后将 localhost.jks 添加到项目中,并修改配置文件
application.properties添加:
server.ssl.trust-store=classpath:localhost.jks
server.ssl.trust-store-password=123456
server.ssl.client-auth=need
注意:此时由于添加了server.ssl.client-auth=need,因为没有添加个人证书,所以这个时候刷新页面,项目会无法访问,如果想要同时兼任普通登录,可以将need改成want,但是want只会在第一次访问页面时才会向客户索取个人证书
创建客户端证书
现在创建一个客户端的证书,步骤和服务端的差不多一样。
openssl req -new -newkey rsa:4096 -nodes -keyout shurlormes.key -out shurlormes.csr
在生成客户端证书时,那些信息不建议跳过,因为在后续的步骤中,会获取其中的信息用以登录。比如我在 Common Name 处填写的信息,就是等下用来登录的用户名。
接下来用 RootCA 给客户端证书签名
openssl x509 -req -CA rootCA.crt -CAkey rootCA.key -in shurlormes.csr -out shurlormes.crt -days 365 -CAcreateserial
然后再将签名证书和私钥打包到 PKCS 文件中
openssl pkcs12 -export -out shurlormes.p12 -name "shurlormes" -inkey shurlormes.key -in shurlormes.crt
最后在 chrome://settings/security 选择 个人证书 把 shurlormes.p12 导入,期间会要你输入它的密码。
这时候刷新页面,浏览器就会弹出一个对话框,让你选择个人认证了。
Spring Boot获取个人证书信息
恭喜你,到了这一步, pki 登录已经完成了 99% 了。接下来就是通过 request 获取证书信息,然后处理字符串,拿到用户名做登录即可。
@RequestMapping("/login")
public String login(HttpServletRequest request) {
X509Certificate[] certs = (X509Certificate[]) request.getAttribute("javax.servlet.request.X509Certificate");
if(certs != null) {
X509Certificate gaX509Cert = certs[0];
String dn = gaX509Cert.getSubjectDN().toString();
System.out.println("个人证书信息:" + dn);
String username = "";
String[] dnArray = dn.split(",");
for (String dnItem : dnArray) {
String[] dnInfo = dnItem.split("=");
String key = dnInfo[0];
String value = dnInfo[1];
if("cn".equalsIgnoreCase(key.trim())) {
username = value;
break;
}
}
System.out.println("用户名:" + username);
if(!StringUtils.isEmpty(username)) {
SecurityContext securityContext = SecurityContextHolder.getContext();
User userDetails = new User(username, "", Collections.EMPTY_LIST);
securityContext.setAuthentication(new UsernamePasswordAuthenticationToken(userDetails, "", Collections.EMPTY_LIST));
return "redirect:/";
}
}
return "login";
}
Spring Boot 同时开启http和https
相信大家都发现了,现在项目只能通过 https 访问,如果用 http 访问浏览器直接返回 Bad request 了。
要同时开启 https 和 http ,只需添加一个 TomcatConfig 就可以
@Configuration
public class TomcatHttpConfig {
@Bean
public TomcatServletWebServerFactory servletContainer() {
TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();
tomcat.addAdditionalTomcatConnectors(initiateHttpConnector());
return tomcat;
}
private Connector initiateHttpConnector() {
Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
connector.setScheme("http");
connector.setPort(9999);
connector.setSecure(false);
return connector;
}
}
这时候启动项目,注意看控制台打印的信息。
说明已经成功启动 http 在端口 9999 , https 在 8888 ,页面也可以成功访问了。
Spring Boot http自动跳转https
上面我们已经可以同时访问 htt p和 https ,但如果我要访问 http 的时候,自动跳转的 https 呢?
只需要在上面的基础上稍微改改就可以了。
@Configuration
public class TomcatHttpConfig {
@Bean
public TomcatServletWebServerFactory servletContainer() {
TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory() {
@Override
protected void postProcessContext(Context context) {
SecurityConstraint securityConstraint = new SecurityConstraint();
securityConstraint.setUserConstraint("CONFIDENTIAL");
SecurityCollection collection = new SecurityCollection();
collection.addPattern("/*");
securityConstraint.addCollection(collection);
context.addConstraint(securityConstraint);
}
};
tomcat.addAdditionalTomcatConnectors(initiateHttpConnector());
return tomcat;
}
private Connector initiateHttpConnector() {
Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
connector.setScheme("http");
connector.setPort(9999);
connector.setSecure(false);
connector.setRedirectPort(8888);
return connector;
}
}
踩坑总结
把服务端证书p12文件添加到项目resources后,记得rebuild项目,否则target的classes中没有生成证书文件,会导致项目启动失败。
application.properties中的server.ssl.keyAlias需要和生成p12文件的-name一致,否则也会导致项目无法启动。
如果要指定域名,需要修改conf.confg中的DNS.1,否则浏览器会提示网站不安全。
代码地址
https://github.com/Shurlormes/pkilogin
参考资料
https://www.baeldung.com/x-509-authentication-in-spring-security
来源:https://segmentfault.com/a/1190000038811117
猜你喜欢
- 首先利用IDEA创建Maven工程项目1.选择新建项目2.选中Maven骨架3.填写项目名称和项目位置4.Finsh之后默认打开的是pom.
- 本文实例为大家分享了Android实现密码明密文切换的具体代码,供大家参考,具体内容如下小眼睛在密码栏右边!奉上我使用的素材:添加图片到re
- Zookeeper和Eureka哪个更好?1、CAP理论一个分布式系统不可能同时很好的满足一致性,可用性和分区容错性这三个需求C:数据一致性
- 本文实例为大家分享了C#仿Windows XP自带的扫雷游戏的具体代码,供大家参考,具体内容如下1 题目描述:模仿Windows XP自带的
- 1 泰勒级数介绍近期工作中需要使用matlab建模,期间做案例的时候有个方程:sin(x)=0,要求不使用现有api进行求解,然后有点懵,不
- 前言相信很多Java开发都遇到过一个面试题:Resource和Autowired的区别是什么?这个问题的答案相信基本都清楚,但是这两者在Sp
- Mybatis与Ibatis的区别: 1、Mybatis实现了接口绑定,使用更加方便 在ibatis2.x中我们需要在DAO的实现类中指定具
- 本文实例总结了Android开发之Button事件实现与监听方法。分享给大家供大家参考,具体如下:先来介绍Button事件实现的两种方法ma
- 分析Github 3000个开源项目,粗略统计如下。括号内的数字是使用频率 0-3000. 下面的列表显示不全,完整的请看完整列表。1.ja
- 前言现在是移动端产品疯狂的年代,随之,移动端支付也是热门小技能,最近本公司在做一个移动端,要接入微信支付和支付宝支付, * 惯,功能做完之后做
- /* * 绘制0°到360°的正弦曲线 * 分两种情形,y>0和y<=0进行绘制 * 每种情形中要
- 最近有一个java实验,要求用java使用数据库,于是本人新手小白,在idea上卡了好半天希望看到这个博客的人能解决问题,跳过一些坑首先,我
- 本文为大家分享了C#导入导出Excel数据的具体代码,供大家参考,具体内容如 * :对于实体类对象最好新建一个并且继承原有实体类,这样可以将类
- 命令模式的介绍命令模式是对命令的封装。命令模式把发出命令的责任和执行命令的责任分割开,委派给不同的对象每一个命令都是一个操作:请求的一方发出
- 一、注解(annotations)列表@SpringBootApplication:包含了@ComponentScan、@Configura
- C语言时用if...else...来控制异常,Java语言所有的异常都可以用一个类来表示,不同类型的异常对应不同的子类异常,每个异常都对应一
- 使用Convert接口实现类型转换器在Spring3中引入了一个Converter接口,它支持从一个Object转为另一个Object。除了
- 一、配置逆向generatoe.xml<?xml version="1.0" encoding="UTF
- 一,授权认证客户端请求服务器时,需要通过授权认证许可,方能获取服务器资源,目前比较常见的认证方式有 Basic 、JWT、Cookie。Ht
- 场景需要判断,首字母是否是英文字母。有人说,那还不简单么,StringUtils.isAlpha() 就可以搞定。 笔者也是这么想的,结果却