在介绍如何添加 HTTPS 前,看复习一下 tomcat 容器的基本配置。在 Spring Boot 项目中,可以内置各种容器。而在使用 spring-boot-starter-web
依赖之后,会默认使用 tomcat 作为容器。以下是在 application.properties 中一些基本配置:
server.port=8088
server.error.path=/404
server.servlet.session.timeout=30m
server.servlet.context-path=/hi
server.tomcat.uri-encoding=utf-8
server.tomcat.basedir=/tmp
其中比较常用的是第一行的端口号配置,以及第四行的 context-path
访问路径配置。最后一行是 Tomcat 运行时,日志和临时文件保存的位置。
HTTPS 配置
理论上来讲 AWS、Google云平台、阿里云等平台都会免费地或收费地提供 HTTPS 服务来保障伺服器的安全性。如果单独买一个 HTTPS 证书的价格也不会特别便宜。好在 JDK 提供了 Java 数字证书管理工具 keytool,生成的命令如下:
keytool -genkey -alias tomcathttps -keyalg RSA -keysize 2048 -keystore tomcat_https.p12 -validity 365
注意它会让你输入一些信息,最重要的就是密码,需要记下来,之后会使用。在这行命令中,
- genkey 是创建一个新密钥
- alias 是这个密钥的别名
- keyalg 提供了加密方法的选择,这里采用的 RSA。(常用的加密方法有以下几种:对称加密的
DES
、3DES
、AES
等,非对称算法 的RSA
、DSA
等 以及 散列算法 的SHA-1
、MD5
等) - keysize 表示密钥的长度
- keystore 指定了密钥保存的位置,注意 .p12 是后缀。
- validity 表示了密钥有效天数
完成后,就会在指定位置生成一个 tomcat_https.p12
文件了。要使用的時候,需要將它放置到项目的根目录下,然后在 application.properties
中做以下配置:
server.ssl.key-store=tomcat_https.p12
server.ssl.key-alias=tomcathttps
server.ssl.key-store-password=657834
配置成功之后,就可以通过 https://localhost:8088
加上其余的地址访问网站了。(由于证书是自己生成的,大部分浏览器还未提供其信任,只需要添加信任之后即可访问)
还需要注意的是, Spring Boot 本身不支持同时在配置中启动 HTTP 和 HTTPS,所以如果现在想要访问 http://localhost:8080
的话,将会报 Bad Request。这里常见的解决方法就是将 HTTP 请求重定向至 HTTPS 的地址,配置方法如下:
package pers.dc.config;
import org.apache.catalina.Context;
import org.apache.catalina.connector.Connector;
import org.apache.tomcat.util.descriptor.web.SecurityCollection;
import org.apache.tomcat.util.descriptor.web.SecurityConstraint;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class TomcatConfig {
@Bean
TomcatServletWebServerFactory tomcatServletWebServerFactory() {
TomcatServletWebServerFactory serverFactory = new TomcatServletWebServerFactory() {
@Override
protected void postProcessContext(Context context) {
SecurityConstraint constraint = new SecurityConstraint();
constraint.setUserConstraint("CONFIDENTIAL");
SecurityCollection collection = new SecurityCollection();
collection.addPattern("/*");
constraint.addCollection(collection);
context.addConstraint(constraint);
}
};
serverFactory.addAdditionalTomcatConnectors(getTomcatInitialConnector());
return serverFactory;
}
private Connector getTomcatInitialConnector() {
Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
connector.setScheme("http");
connector.setPort(8088);
connector.setSecure(false);
connector.setRedirectPort(8080);
return connector;
}
}
这样,在访问 8088
端口的 HTTP 访问时,就会被重定向之前的 8080
的 HTTPS 加密地址了。(注意:两个地址不能一样,不然会报错。)