Spring Boot 2.x-自动将HTTP重定向到HTTPS



我一直在试图找到以下问题的简单答案:
"如何配置SpringBoot2.x以自动将请求从HTTP重定向到HTTPS">

所涉及的Spring类似乎已经从Spring Boot 1.x更改为2.x,所以已经为Spring Boot 1.x询问/回答了这个问题的人留下了在2.x中不再有效的信息。我能够自己从各种来源找到解决方案,所以我将回答我自己的问题。如果其他人有更清洁的解决方案,那么我会接受它,并可能在我自己的应用程序中使用它。

解决这个问题的"挑战"是,似乎没有一个简单的仅配置的解决方案来让嵌入式Tomcatservlet容器侦听两个端口。如果有办法的话,那么我还没有找到。需要少量编码才能将自定义Connector添加到TomcatServletWebServerFactory,然后将连接器配置为在第二个端口(HTTP端口(上侦听并重定向到HTTPS端口。

我的解决方案是实现WebServerFactoryCustomizer接口,并将自定义Connector添加到web服务器工厂实例中。

@Component
public class MyWebServerFactoryCustomizer implements WebServerFactoryCustomizer<TomcatServletWebServerFactory> {
private static final Logger LOGGER = LoggerFactory.getLogger(MyWebServerFactoryCustomizer.class);
@PostConstruct
void postConstruct() {
LOGGER.debug("postConstruct() | INVOKED");
}
private final int httpPort;
private final int redirectToHttpsPort;
@Autowired
MyWebServerFactoryCustomizer(
@Value("${server.http.port}") int httpPort,
@Value("${server.redirect.to.https.port}") int redirectToHttpsPort) {
this.httpPort = httpPort;
this.redirectToHttpsPort = redirectToHttpsPort;
}
@Override
public void customize(TomcatServletWebServerFactory factory) {
factory.addAdditionalTomcatConnectors(redirectConnector());
}
private Connector redirectConnector() {
Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
connector.setScheme("http");
connector.setPort(httpPort);
connector.setSecure(false);
connector.setRedirectPort(redirectToHttpsPort);
return connector;
}
}

在我的application.properties文件中,我需要提供两个端口号的值,以及与提供安全HTTPS连接的密钥库相关的一些其他内容:

#--------------------------------------------------------------------------------------------------
# SSL CONFIGURATION
server.ssl.key-store-type=PKCS12
server.ssl.key-store=classpath:keystore/jimtough-dot-org-keystore.pkcs12
server.ssl.key-store-password=mykeystorepassword
server.ssl.key-alias=jimtough-dot-org
server.ssl.enabled=true
server.port=8443
# These two are not standard property keys. I use them to map the HTTP port to the HTTPS port.
server.http.port=8080
server.redirect.to.https.port=8443
#--------------------------------------------------------------------------------------------------

我的解决方案还需要一些额外的Spring Security配置,如下所示:

@Configuration
@EnableWebSecurity
public class SpringSecurityConfiguration extends WebSecurityConfigurerAdapter {
private final int httpPort;
private final int redirectToHttpsPort;
@Autowired
SpringSecurityConfiguration(
@Value("${server.http.port}") int httpPort,
@Value("${server.redirect.to.https.port}") int redirectToHttpsPort) {
this.httpPort = httpPort;
this.redirectToHttpsPort = redirectToHttpsPort;
}
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.authorizeRequests(authorize -> {
// The following paths do not require the user to be authenticated by Spring Security
authorize.antMatchers("/", "/favicon.ico", "/login", "/vendor/**").permitAll();
})
// All other request paths not covered by the list above can only be viewed by an authenticated user
.authorizeRequests().anyRequest().authenticated()
.and()
.portMapper().http(httpPort).mapsTo(redirectToHttpsPort)
.and()
.requiresChannel().anyRequest().requiresSecure()
.and()
// This should redirect HTTP requests to HTTPS
.formLogin()
.and()
// Use HTTP Basic authentication
.httpBasic();
}
}

上面的相关部分是.portMapper().http(httpPort).mapsTo(redirectToHttpsPort).requiresChannel().anyRequest().requiresSecure()比特。这将强制请求者自动从HTTP转换为HTTPS。

请注意,我的解决方案使用了三个配置属性:

  • server.port
  • server.http.port
  • server.redirect.to.https.port

这可以简化为只使用两个属性(只要在我使用过server.redirect.to.https.port的地方使用server.port(。我有一个特殊情况,我仍在努力解决,它需要我添加第三个配置属性。你可能不需要它。


如果您刚刚开始使用HTTPS和Spring Boot,并且根本不知道如何启用HTTPS,那么https://stackoverflow.com/a/65384432/346112你可能也感兴趣。


还有一点需要注意。我最终选择在服务器上的Spring Boot应用程序前面使用"nginx"作为反向代理。这将SSL/HTTPS配置提升到了一个更高的级别,并允许nginx终止HTTPS连接,并将流量未加密地转发到我的Spring Boot应用程序。我认为这是一个更好的解决方案。我不再需要麻烦Java密钥库或任何Spring Boot/TTomcat配置来监听多个端口、转发流量等。Spring Boot可以在HTTP上用8080端口愉快地运行,剩下的由nginx处理。这确实需要application.properties:中的一些Spring Boot设置

server.port=8080
server.ssl.enabled=false
server.forward-headers-strategy=NATIVE
# optional
server.servlet.session.timeout=1d
server.servlet.session.cookie.max-age=1d

最新更新