Spring Boot将HTTP重定向到HTTPS

时间:2014-10-30 14:38:21

标签: java http spring-boot redirect https

对于基于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

我在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;
}

但是当我通过

尝试以下内容时
http://127.0.0.1:9090/

重定向到

https://127.0.0.1:8443/

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

10 个答案:

答案 0 :(得分:31)

要使Tomcat执行重定向,您需要使用一个或多个安全约束对其进行配置。您可以使用Context子类对TomcatEmbeddedServletContainerFactory进行后处理来完成此操作。

例如:

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);
    }
};

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

答案 1 :(得分:26)

在应用程序* .properties文件上设置此属性(以及在代理服务器后面运行的HTTPS标头的相应servlet特定配置)并设置Spring Security(例如,使用 org.springframework)。启动:类路径上的spring-boot-starter-security 应该足够了:

security.require-ssl=true

现在,出于某种原因,在禁用基本身份验证时(至少在旧版本的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();
    }
}

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

security.require-ssl=true

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

答案 2 :(得分:9)

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

我还必须将以下内容添加到我的Web安全配置中,因为我没有使用默认的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();
    }
}

答案 3 :(得分:6)

只需要两个步骤。

1-在pom.xml中添加spring security依赖项

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

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

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

答案 4 :(得分:5)

在Spring-Boot中,需要低于依赖项

第1步

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

第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

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

  

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

第4步,将证书移至程序中的resources文件夹。

第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;
    }
}

就是这样。

答案 5 :(得分:3)

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

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);
    }
}

然后通过添加一个实现@Configuration的{​​{1}}类以及一个侦听非安全端口的新EmbeddedServletContainerCustomizer来连接此类:

Connector

这意味着已配置SSL @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); }); } } 并在此示例中侦听端口443。

答案 6 :(得分:3)

TomcatEmbeddedServletContainerFactory has been removed在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);
        }
    };
}

答案 7 :(得分:0)

对于Spring Boot 2,我已经使用以下@Configuration配置了资源服务器:

@Configuration
@EnableResourceServer
public class ResourceServer extends ResourceServerConfigurerAdapter {

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http
            .requiresChannel()
                /* Require HTTPS evereywhere*/
                .antMatchers("/**")
                    .requiresSecure();
    }    
}

基本上就是

答案 8 :(得分:0)

@EnableWebSecurity
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

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

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

为避免无限重定向循环(已在gcloud上使用) 将此行添加到应用程序属性中:

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

答案 9 :(得分:0)

使用拦截器发送重定向到https://

(不需要Spring Security)

这些似乎都很复杂。为什么我们不只是添加一个检查端口的拦截器,如果它是端口80,则将其重定向到相同的URL,但以https://开头。

@Component
public class HttpsConfig implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        // String requestedPort = request.getServerPort() if you're not behind a proxy
        String requestedPort = request.getHeader("X-Forwarded-Port"); // I'm behind a proxy on Heroku

        if (requestedPort != null && requestedPort.equals("80")) { // This will still allow requests on :8080
            response.sendRedirect("https://" + request.getServerName() + request.getRequestURI() + (request.getQueryString() != null ? "?" + request.getQueryString() : ""));
            return false;
        }
        return true;
    }

}

别忘了注册您可爱的拦截器

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new HttpsConfig());
    }
}

注意:您的生产Web服务器通常将在1个或2个端口(80个不安全的443安全)上运行,并且您应该知道它们是什么,所以我认为这不是很多允许其他端口存在安全风险。