springboot2.x-自动将http重定向到https

biswetbf  于 2021-06-30  发布在  Java
关注(0)|答案(1)|浏览(557)

我一直在试图找到以下问题的简单答案:
“如何配置SpringBoot2.x以自动将请求从http重定向到https?”
所涉及的spring类似乎已从springboot1.x更改为2.x,因此已经为springboot1.x提问/回答过这个问题的人留下了在2.x中不再有效的信息。我能从各种渠道自己找出解决办法,所以我要回答我自己的问题。如果其他人有更干净的解决方案,那么我会接受它,并可能在我自己的应用程序中使用它。
解决这个问题的“挑战”在于,要使嵌入式tomcatservlet容器侦听两个端口,似乎没有一个简单的仅配置的解决方案。如果有办法,那我还没找到。需要少量编码才能添加自定义 ConnectorTomcatServletWebServerFactory ,然后将连接器配置为侦听第二个端口(http端口)并重定向到https端口。

yhqotfr8

yhqotfr81#

我的解决办法是实施 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安全配置,如下所示:

@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.port 我用过的地方 server.redirect.to.https.port ). 我有一个特殊的情况,我仍在努力解决,需要我添加第三个配置属性。你可能不需要它。
如果您刚刚开始使用https和spring boot,并且根本不知道如何启用https,那么https://stackoverflow.com/a/65384432/346112 你可能也感兴趣。
还有一个注意事项。我最终选择使用“nginx”作为服务器上spring引导应用程序前面的反向代理。这将ssl/https配置提升到了一个更高的级别,并允许nginx终止https连接,并将流量未加密地转发到我的spring boot应用程序。我认为这是一个更好的解决办法。我再也不需要乱用java密钥库或spring-boot/tomcat配置来监听多个端口、转发流量等。spring-boot只需在带有8080端口的http上愉快地运行,剩下的就让nginx来处理。这确实需要一些spring引导设置 application.properties :

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

相关问题