Spring 启动:Tomcat 重定向到 HTTPS 8443,无论我指定哪个 HTTPS 端口
Spring Boot: Tomcat redirects to HTTPS 8443, no matter which HTTPS port I specify
我使用相当标准的方法将 Spring Boot 的嵌入式 Tomcat 从 HTTP 重定向到 HTTPS,这在许多教程中重复出现。该方法非常适用于端口 HTTP 8080 和 HTTPS 8443,这些端口也在本教程中重复作为示例。但是,如进一步所述,将这些端口的数量更改为较少使用的值会产生许多问题。
教程中的方法如下。应用属性:
server.http.port=8080
server.http.interface=0.0.0.0
server.port: 8443
server.ssl.enabled: true
server.ssl.key-store: classpath:selfsigned.jks
server.ssl.key-store-password: password
server.ssl.key-store-type: JKS
server.ssl.key-alias: selfsigned
然后配置额外的HTTP端口:
@Component
public class HttpServer {
@Value("${server.port}") int HTTPS_PORT;
@Bean
public ServletWebServerFactory servletContainer(@Value("${server.http.port}") int httpPort) {
Connector connector = new Connector(TomcatServletWebServerFactory.DEFAULT_PROTOCOL);
connector.setPort(httpPort);
connector.setRedirectPort(HTTPS_PORT);
TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory() {
@Override
protected void postProcessContext(Context context) {
((StandardJarScanner) context.getJarScanner()).setScanManifest(false);
}
};
tomcat.addAdditionalTomcatConnectors(connector);
return tomcat;
}
}
最后,安全配置:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception{
http.cors().and().csrf().disable();
http.requiresChannel().anyRequest().requiresSecure();
http.headers().frameOptions().sameOrigin();
http.portMapper()
.http(Integer.parseInt(Prop.get("server.http.port")))
.mapsTo(Integer.parseInt(Prop.get("server.port")));
}
@Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("*"));
configuration.setAllowedMethods(Arrays.asList("*"));
configuration.setAllowedHeaders(Arrays.asList("*"));
configuration.setAllowCredentials(true);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}
与教程的唯一区别是我禁用了 TomcatServletWebServerFactory
中的 Jar 清单文件扫描,否则如果包含 tomcat-embed-jasper
就会出现问题(参见 )。
这个:
server.http.port=8080
server.port: 8443
如我所说,与教程中的一样完美。这个:
server.http.port=8080
server.port: 5001
仍然重定向到 HTTPS 8443,但 8443 没有任何内容,因为 Tomcat 在 8080 和 5001 侦听:
INFO 7360 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 5001 (https) 8080 (http) with context path ''
我扫描了 8443
我应用程序中的每个文件,包括源代码和二进制文件。那里没有 8443
的单个实例。我还使用调试器来验证 setPort()
、setRedirectPort()
和 portMapper()
.
中的值是否正确
这个:
server.http.port=5000
server.port: 5001
产生:
0:0:0:0:0:0:0:1 - - [28/Jan/2021:18:44:46 +0100] "GET /a HTTP/1.1" 302 -
0:0:0:0:0:0:0:1 - - [28/Jan/2021:18:44:46 +0100] "GET /a HTTP/1.1" 302 -
0:0:0:0:0:0:0:1 - - [28/Jan/2021:18:44:46 +0100] "GET /a HTTP/1.1" 302 -
0:0:0:0:0:0:0:1 - - [28/Jan/2021:18:44:46 +0100] "GET /a HTTP/1.1" 302 -
...
直到浏览器抱怨重定向太多。
站点已在 localhost
上测试,证书无效,因此 Chrome 请求安全例外。尽管如此,Chrome 仍将站点置于 HTTP 严格传输安全中,这可以在 chrome://net-internals/#hsts
进行验证。 Spring Boot 会在 HSTS headers 中发送一些内容导致重定向到 8443 吗?
总而言之,8080
和 8443
似乎有些特殊并在某处声明,可能在 Tomcat 或 Spring 引导中。 如何摆脱这些默认值? 任何调试方式,例如重定向背后的原因?增加 Tomcat、Spring 引导日志的详细程度?
更新1为了禁用HSTS,我修改了安全码:
http.headers().frameOptions().sameOrigin()
.httpStrictTransportSecurity().disable();
并从 Chrome' HSTS 中删除了 localhost
,但没有帮助。
更新 2 当应用程序 运行 在具有有效证书的外部服务器上时问题仍然存在。
项目依赖项:
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>org.projectreactor</groupId>
<artifactId>reactor-spring</artifactId>
<version>1.0.1.RELEASE</version>
</dependency>
这是没有意义的spring无论你配置哪个端口,团队都坚持使用8443。详情见
https://github.com/spring-projects/spring-security/issues/8140
https://github.com/spring-projects/spring-boot/issues/6140
我使用相当标准的方法将 Spring Boot 的嵌入式 Tomcat 从 HTTP 重定向到 HTTPS,这在许多教程中重复出现。该方法非常适用于端口 HTTP 8080 和 HTTPS 8443,这些端口也在本教程中重复作为示例。但是,如进一步所述,将这些端口的数量更改为较少使用的值会产生许多问题。
教程中的方法如下。应用属性:
server.http.port=8080
server.http.interface=0.0.0.0
server.port: 8443
server.ssl.enabled: true
server.ssl.key-store: classpath:selfsigned.jks
server.ssl.key-store-password: password
server.ssl.key-store-type: JKS
server.ssl.key-alias: selfsigned
然后配置额外的HTTP端口:
@Component
public class HttpServer {
@Value("${server.port}") int HTTPS_PORT;
@Bean
public ServletWebServerFactory servletContainer(@Value("${server.http.port}") int httpPort) {
Connector connector = new Connector(TomcatServletWebServerFactory.DEFAULT_PROTOCOL);
connector.setPort(httpPort);
connector.setRedirectPort(HTTPS_PORT);
TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory() {
@Override
protected void postProcessContext(Context context) {
((StandardJarScanner) context.getJarScanner()).setScanManifest(false);
}
};
tomcat.addAdditionalTomcatConnectors(connector);
return tomcat;
}
}
最后,安全配置:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception{
http.cors().and().csrf().disable();
http.requiresChannel().anyRequest().requiresSecure();
http.headers().frameOptions().sameOrigin();
http.portMapper()
.http(Integer.parseInt(Prop.get("server.http.port")))
.mapsTo(Integer.parseInt(Prop.get("server.port")));
}
@Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("*"));
configuration.setAllowedMethods(Arrays.asList("*"));
configuration.setAllowedHeaders(Arrays.asList("*"));
configuration.setAllowCredentials(true);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}
与教程的唯一区别是我禁用了 TomcatServletWebServerFactory
中的 Jar 清单文件扫描,否则如果包含 tomcat-embed-jasper
就会出现问题(参见
这个:
server.http.port=8080
server.port: 8443
如我所说,与教程中的一样完美。这个:
server.http.port=8080
server.port: 5001
仍然重定向到 HTTPS 8443,但 8443 没有任何内容,因为 Tomcat 在 8080 和 5001 侦听:
INFO 7360 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 5001 (https) 8080 (http) with context path ''
我扫描了 8443
我应用程序中的每个文件,包括源代码和二进制文件。那里没有 8443
的单个实例。我还使用调试器来验证 setPort()
、setRedirectPort()
和 portMapper()
.
这个:
server.http.port=5000
server.port: 5001
产生:
0:0:0:0:0:0:0:1 - - [28/Jan/2021:18:44:46 +0100] "GET /a HTTP/1.1" 302 -
0:0:0:0:0:0:0:1 - - [28/Jan/2021:18:44:46 +0100] "GET /a HTTP/1.1" 302 -
0:0:0:0:0:0:0:1 - - [28/Jan/2021:18:44:46 +0100] "GET /a HTTP/1.1" 302 -
0:0:0:0:0:0:0:1 - - [28/Jan/2021:18:44:46 +0100] "GET /a HTTP/1.1" 302 -
...
直到浏览器抱怨重定向太多。
站点已在 localhost
上测试,证书无效,因此 Chrome 请求安全例外。尽管如此,Chrome 仍将站点置于 HTTP 严格传输安全中,这可以在 chrome://net-internals/#hsts
进行验证。 Spring Boot 会在 HSTS headers 中发送一些内容导致重定向到 8443 吗?
总而言之,8080
和 8443
似乎有些特殊并在某处声明,可能在 Tomcat 或 Spring 引导中。 如何摆脱这些默认值? 任何调试方式,例如重定向背后的原因?增加 Tomcat、Spring 引导日志的详细程度?
更新1为了禁用HSTS,我修改了安全码:
http.headers().frameOptions().sameOrigin()
.httpStrictTransportSecurity().disable();
并从 Chrome' HSTS 中删除了 localhost
,但没有帮助。
更新 2 当应用程序 运行 在具有有效证书的外部服务器上时问题仍然存在。
项目依赖项:
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>org.projectreactor</groupId>
<artifactId>reactor-spring</artifactId>
<version>1.0.1.RELEASE</version>
</dependency>
这是没有意义的spring无论你配置哪个端口,团队都坚持使用8443。详情见 https://github.com/spring-projects/spring-security/issues/8140 https://github.com/spring-projects/spring-boot/issues/6140