Springboot加入HTTPS功能
HTTPS:
超文本传输安全协议(HyperText Transfer Protocol Secure),缩写:HTTPS;常称为 HTTP over TLS、HTTP over SSL 或 HTTP Secure)是一种通过计算机网络进行安全通信的传输协议。HTTPS 经由 HTTP进行通信,但利用 SSL/TLS 来加密数据包。HTTPS 开发的主要目的,是提供对网站服务器的身份认证,保护交换数据的隐私与完整性。这个协议由网景公司(Netscape)在 1994 年首次提出,随后扩展到互联网上。
- 生成HTTPS数字证书
借助 Java 自带的 JDK 管理工具 keytool 来生成一个免费的 https 证书;
进入到 %JAVVA_HOME%\bin 目录下,执行如下命令生成一个数字证书:
keytool -genkey -alias tomcathttps -keyalg RSA -keysize 2048 -keystore D:\Zhangjian_HTTPS_digital_certificate.p12 -validity 365
命令含义如下:
- genkey 表示要创建一个新的密钥。
- alias 表示 keystore 的别名。
- keyalg 表示使用的加密算法是 RSA ,一种非对称加密算法。
- keysize 表示密钥的长度。
- keystore 表示生成的密钥存放位置。
- validity 表示密钥的有效时间,单位为天。
- 引入HTTPS
将上面生成的Zhangjian_HTTPS_digital_certificate .p12
拷贝到 Spring Boot 项目的 resources 目录下;
然后在 application.properties 中添加如下配置:
# 引入HTTPS数字证书
server.ssl.key-store=classpath:Zhangjian_HTTPS_digital_certificate.p12
server.ssl.key-alias=tomcathttps
server.ssl.key-store-password=zjroot
启动项目,直接使用 Http 协议来访问接口,就会看到如下错误:
改用 https 来访问 ,结果如下:
“不安全”:这是因为我们自己生成的 https 证书不被浏览器认可,不过没关系,我们直接点击继续访问就可以了(实际项目中只需要更换一个被浏览器认可的 https 证书即可);
- 请求转发
考虑到 Spring Boot 不支持同时启动 HTTP 和 HTTPS ,为了解决这个问题,我们这里可以配置一个请求转发,当用户发起 HTTP 调用时,自动转发到 HTTPS 上;- 新建配置类TomcatConfig
- 新建配置类TomcatConfig
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 factory = 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);
}
};
factory.addAdditionalTomcatConnectors(createTomcatConnector());
return factory;
}
private Connector createTomcatConnector() {
Connector connector = new
Connector("org.apache.coyote.http11.Http11NioProtocol");
connector.setScheme("http");
connector.setPort(8081);
connector.setSecure(false);
connector.setRedirectPort(8080);
return connector;
}
}
在这里,我们配置了 Http 的请求端口为 8081,所有来自 8081 的请求,将被自动重定向到 8080 这个 https 的端口上。
如此之后,我们再去访问 http 请求,就会自动重定向到 https;
测试:
成功转向了HTTPS;
手动生成Springboot的Starter
我们使用 Spring Boot,基本上都是沉醉在它 Stater 的方便之中。Starter 为我们带来了众多的自动化配置,有了这些自动化配置,我们可以不费吹灰之力就能搭建一个生产级开发环境,有的小伙伴会觉得这个 Starter 好神奇呀!其实 Starter 也都是 Spring + SpringMVC 中的基础知识点实现的;
其实 Starter 的核心就是条件注解 @Conditional ,当 classpath 下存在某一个 Class 时,某个配置才会生效;
- 自定义Starter
所谓的 Starter ,其实就是一个普通的 Maven 项目,因此我们自定义 Starter ,需要首先创建一个普通的 Maven 项目,创建完成后,在pom.xml
中添加 Starter 的自动化配置类即可,如下:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<version>2.1.4.RELEASE</version>
</dependency>
配置完成后,我们首先创建一个 HelloProperties 类,用来接受 application.properties 中注入的值,如下:
package com.zhangjian.springboot.springboot_learn_002;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties(prefix = "zhangjian")
public class HelloProperties {
private static final String DEFAULT_NAME = "ZhangJian";
private static final String DEFAULT_MSG = "hello~";
private String name = DEFAULT_NAME;
private String msg = DEFAULT_MSG;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
报错,加上Component解决;
解决Configuration Annotation Proessor not found in classpath
如下:
- 出现spring boot Configuration Annotation Proessor not found in classpath的提示是在用了@ConfigurationProperties这个注解时,所以问题出现在2. ConfigurationProperties注解。
- 根据提示的not found in classpath,查询此注解的使用关于怎么指定classpath,进而查询location,spring boot1.5以上版本@ConfigurationProperties取消location注解;
官方解决方案,Maven引入依赖:
<dependency>
<groupId> org.springframework.boot </groupId>
<artifactId> spring-boot-configuration-processor </artifactId>
<optional> true </optional>
</dependency>
回到HelloProperties类,这个配置类很好理解,将 application.properties 中配置的属性值直接注入到这个实例中, @ConfigurationProperties 类型安全的属性注入,即将 application.properties 文件中前缀为 zhangjian
的属性注入到这个类对应的属性上, 最后使用的时候,application.properties 中的配置文件,大概如下:
配置完成 HelloProperties 后,接下来我们来定义一个 HelloService ,然后定义一个简单的 say 方法, HelloService 的定义如下:
package com.zhangjian.springboot.springboot_learn_002;
public class HelloService {
private String msg;
private String name;
public String sayHello() {
return name + " say " + msg + " !";
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
接下来就是我们的重轴戏,自动配置类的定义,用了很多别人定义的自定义类之后,我们也来自己定义一个自定义类HelloServiceAutoConfiguration
:
package com.zhangjian.springboot.springboot_learn_002;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableConfigurationProperties(HelloProperties.class)
@ConditionalOnClass(HelloService.class)
public class HelloServiceAutoConfiguration {
@Autowired
HelloProperties helloProperties;
@Bean
HelloService helloService() {
HelloService helloService = new HelloService();
helloService.setName(helloProperties.getName());
helloService.setMsg(helloProperties.getMsg());
return helloService;
}
}
解释如下:
- 首先 @Configuration 注解表明这是一个配置类。
- @EnableConfigurationProperties 注解是使我们之前配@ConfigurationProperties 生效,让配置的属性成功的进入 Bean 中。
- @ConditionalOnClass 表示当项目当前 classpath 下存在 HelloService 时,后面的配置才生效。
- 自动配置类中首先注入 HelloProperties ,这个实例中含有我们在 application.properties 中配置的相关数据。
- 提供一个 HelloService 的实例,将 HelloProperties 中的值注入进去。