Java Spring Boot 将 HTTP 重定向到 HTTPS

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/26655875/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 03:01:08  来源:igfitidea点击:

Spring Boot redirect HTTP to HTTPS

javahttpspring-bootredirecthttps

提问by Arseniy Ulakaiev

For Spring Boot based application I have configurared ssl properties at application.properties, see my configuration here:

对于基于 Spring Boot 的应用程序,我在 application.properties 配置了 ssl 属性,请在此处查看我的配置:

server.port=8443
server.ssl.key-alias=tomcat
server.ssl.key-password=123456
server.ssl.key-store=classpath:key.p12
server.ssl.key-store-provider=SunJSSE
server.ssl.key-store-type=pkcs12

And I have added conection at Application.class, like

我在 Application.class 上添加了连接,比如

@Bean
public EmbeddedServletContainerFactory tomcatEmbeddedServletContainerFactory() {
    final TomcatEmbeddedServletContainerFactory factory = new TomcatEmbeddedServletContainerFactory();
    factory.addAdditionalTomcatConnectors(this.createConnection());
    return factory;
}

private Connector createConnection() {
    final String protocol = "org.apache.coyote.http11.Http11NioProtocol";
    final Connector connector = new Connector(protocol);

    connector.setScheme("http");
    connector.setPort(9090);
    connector.setRedirectPort(8443);
    return connector;
}

But when I try the following by

但是当我尝试以下操作时

http://127.0.0.1:9090/

redirect to

重定向到

https://127.0.0.1:8443/

is not performed. Who faced a similar problem?

不执行。谁遇到过类似的问题?

采纳答案by Andy Wilkinson

For Tomcat to perform a redirect, you need to configure it with one or more security constraints. You can do this by post-processing the Contextusing a TomcatEmbeddedServletContainerFactorysubclass.

要让 Tomcat 执行重定向,您需要为其配置一个或多个安全约束。您可以通过Context使用TomcatEmbeddedServletContainerFactory子类对进行后处理来做到这一点。

For example:

例如:

TomcatEmbeddedServletContainerFactory tomcat = new TomcatEmbeddedServletContainerFactory() {
    @Override
    protected void postProcessContext(Context context) {
        SecurityConstraint securityConstraint = new SecurityConstraint();
        securityConstraint.setUserConstraint("CONFIDENTIAL");
        SecurityCollection collection = new SecurityCollection();
        collection.addPattern("/*");
        securityConstraint.addCollection(collection);
        context.addConstraint(securityConstraint);
    }
};

Due to CONFIDENTIALand /*, this will cause Tomcat to redirect every request to HTTPS. You can configure multiple patterns and multiple constraints if you need more control over what is and is not redirected.

由于CONFIDENTIAL/*,这将导致 Tomcat 将每个请求重定向到 HTTPS。如果您需要更多地控制重定向和未重定向的内容,您可以配置多个模式和多个约束。

回答by jebeaudet

For Jetty (tested with 9.2.14), you need to add an extra configuration to the WebAppContext(adjust the pathSpecto your taste) :

对于 Jetty(用 9.2.14 测试),您需要添加额外的配置WebAppContextpathSpec根据您的喜好调整):

import org.eclipse.jetty.security.ConstraintMapping;
import org.eclipse.jetty.security.ConstraintSecurityHandler;
import org.eclipse.jetty.util.security.Constraint;
import org.eclipse.jetty.webapp.AbstractConfiguration;
import org.eclipse.jetty.webapp.WebAppContext;

class HttpToHttpsJettyConfiguration extends AbstractConfiguration
{
    // http://wiki.eclipse.org/Jetty/Howto/Configure_SSL#Redirecting_http_requests_to_https
    @Override
    public void configure(WebAppContext context) throws Exception
    {
        Constraint constraint = new Constraint();
        constraint.setDataConstraint(2);

        ConstraintMapping constraintMapping = new ConstraintMapping();
        constraintMapping.setPathSpec("/*");
        constraintMapping.setConstraint(constraint);

        ConstraintSecurityHandler constraintSecurityHandler = new ConstraintSecurityHandler();
        constraintSecurityHandler.addConstraintMapping(constraintMapping);

        context.setSecurityHandler(constraintSecurityHandler);
    }
}

Then wire this class by adding an @Configurationclass implementing EmbeddedServletContainerCustomizeralong with a new Connectorthat listen to the non secure port :

然后通过添加一个@Configuration实现类EmbeddedServletContainerCustomizer和一个新的Connector监听非安全端口的类来连接这个类:

@Configuration
public class HttpToHttpsJettyCustomizer implements EmbeddedServletContainerCustomizer
{
    @Override
    public void customize(ConfigurableEmbeddedServletContainer container)
    {
        JettyEmbeddedServletContainerFactory containerFactory = (JettyEmbeddedServletContainerFactory) container;
        //Add a plain HTTP connector and a WebAppContext config to force redirect from http->https
        containerFactory.addConfigurations(new HttpToHttpsJettyConfiguration());

        containerFactory.addServerCustomizers(server -> {
            HttpConfiguration http = new HttpConfiguration();
            http.setSecurePort(443);
            http.setSecureScheme("https");

            ServerConnector connector = new ServerConnector(server);
            connector.addConnectionFactory(new HttpConnectionFactory(http));
            connector.setPort(80);

            server.addConnector(connector);
        });
    }
}

This implies that the SSL Connectoris already configured and listening on port 443 in this example.

这意味着 SSLConnector已在此示例中配置并侦听端口 443。

回答by Rodrigo Quesada

Setting this property on your application*.properties file (and the corresponding servlet-specific configuration for HTTPS headers in case you are running behind a proxy) and having Spring Security set-up (e.g. having org.springframework.boot:spring-boot-starter-securityon your classpath) should be enough:

在您的 application*.properties 文件上设置此属性(以及 HTTPS 标头的相应 servlet 特定配置,以防您在代理后面运行)并设置 Spring Security(例如,具有org.springframework.boot:spring-boot-类路径上的starter-security)应该足够了:

security.require-ssl=true

Now, for some reason that configuration is not honored when basic authentication is disabled (at least on old versions of Spring Boot). So in that case you would need to take an extra step and honor it yourself by manually configuring the security on your code, like this:

现在,出于某种原因,当禁用基本身份验证(至少在旧版本的 Spring Boot 上)时,配置将不被遵守。因此,在这种情况下,您需要采取额外的步骤并通过手动配置代码的安全性来实现它,如下所示:

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Inject private SecurityProperties securityProperties;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        if (securityProperties.isRequireSsl()) http.requiresChannel().anyRequest().requiresSecure();
    }
}

So, in case you are using Tomcat behind a proxy, you would have all these properties on your application*.properties file:

因此,如果您在代理后面使用 Tomcat,您的 application*.properties 文件中将拥有所有这些属性:

security.require-ssl=true

server.tomcat.remote_ip_header=x-forwarded-for
server.tomcat.protocol_header=x-forwarded-proto

回答by Alex Burdusel

The approved answer was not enough for me.

批准的答案对我来说还不够。

I had to also add the following to my web security config, as I am not using the default 8080 port:

我还必须将以下内容添加到我的网络安全配置中,因为我没有使用默认的 8080 端口:

@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private Environment environment;

    @Override
    public void configure(HttpSecurity http) throws Exception {
        // other security configuration missing

        http.portMapper()
                .http(Integer.parseInt(environment.getProperty("server.http.port"))) // http port defined in yml config file
                .mapsTo(Integer.parseInt(environment.getProperty("server.port"))); // https port defined in yml config file

        // we only need https on /auth
        http.requiresChannel()
                .antMatchers("/auth/**").requiresSecure()
                .anyRequest().requiresInsecure();
    }
}

回答by rogue lad

Follow only 2 steps.

只需执行 2 个步骤。

1- Add spring security dependency in pom.xml

1- 在 pom.xml 中添加 spring 安全依赖

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>

2- Add this class on root package of your application.

2- 在应用程序的根包上添加此类。

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.requiresChannel().anyRequest().requiresSecure();
    }
}

回答by Mahozad

Since TomcatEmbeddedServletContainerFactoryhas been removedin Spring Boot 2, use this:

由于TomcatEmbeddedServletContainerFactory在 Spring Boot 2 中删除,请使用:

@Bean
public TomcatServletWebServerFactory httpsRedirectConfig() {
    return new TomcatServletWebServerFactory () {
        @Override
        protected void postProcessContext(Context context) {
            SecurityConstraint securityConstraint = new SecurityConstraint();
            securityConstraint.setUserConstraint("CONFIDENTIAL");
            SecurityCollection collection = new SecurityCollection();
            collection.addPattern("/*");
            securityConstraint.addCollection(collection);
            context.addConstraint(securityConstraint);
        }
    };
}

回答by Arvind Pant

In Spring-Boot, need below dependency

在 Spring-Boot 中,需要以下依赖项

Step 1-

第1步-

<dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-web</artifactId>
</dependency>

Step 2- Just need to do below configurations on application.properties file

步骤 2- 只需要对 application.properties 文件进行以下配置

 - server.port=8443
 - server.ssl.key.alias=ode-https
 - server.ssl.key-store-type=JKS (just for testing i USED JSK, but for production normally use pkcs12)
 - server.ssl.key-password=password
 - server.ssl.key-store=classpath:ode-https.jks

Step 3- now need to generate a certificate using the above details.

第 3 步 - 现在需要使用上述详细信息生成证书。

keytool -genkey -alias ode-https -storetype JKS -keyalg RSA -keys ize 2048 -validity 365 -keystore ode-https.jks

keytool -genkey -alias ode-https -storetype JKS -keyalg RSA -keys ize 2048 -validity 365 -keystore ode-https.jks

Step 4- move the certificate to resources folder in your program.

第 4 步 - 将证书移动到程序中的资源文件夹。

Step 5- Create config class

第 5 步 - 创建配置类

@Configuration
public class HttpsConfiguration {
    @Bean
    public ServletWebServerFactory servletContainer() {
        TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory() {
            @Override
            protected void postProcessContext(Context context) {
                SecurityConstraint securityConstraint = new SecurityConstraint();
                securityConstraint.setUserConstraint("CONFIDENTIAL");
                SecurityCollection collection = new SecurityCollection();
                collection.addPattern("/*");
                securityConstraint.addCollection(collection);
                context.addConstraint(securityConstraint);
            }
        };
        tomcat.addAdditionalTomcatConnectors(redirectConnector());
        return tomcat;
    }

    @Value("${server.port.http}") //Defined in application.properties file
    int httpPort;

    @Value("${server.port}") //Defined in application.properties file
    int httpsPort;

    private Connector redirectConnector() {
        Connector connector = new Connector(TomcatServletWebServerFactory.DEFAULT_PROTOCOL);
        connector.setScheme("http");
        connector.setPort(httpPort);
        connector.setSecure(false);
        connector.setRedirectPort(httpsPort);
        return connector;
    }
}

that's it.

就是这样。

回答by Vladislav Troyan

@EnableWebSecurity
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http.requiresChannel().anyRequest().requiresSecure();   
    }
}

To avoid endless redirect loop (has it on gcloud) add this lines to application properties:

为避免无休止的重定向循环(在 gcloud 上有),将此行添加到应用程序属性中:

server.tomcat.remote_ip_header=x-forwarded-for 
server.tomcat.protocol_header=x-forwarded-proto