如何在Heroku下的java cedar堆栈中强制执行HTTPS

时间:2012-08-09 21:16:22

标签: java heroku https

我发现很多关于在heroku下强制执行HTTPS的问题,但没有回复关于java。

以下是我找到的链接:

斯卡拉:http://www.andersen-gott.com/2012/03/using-unfiltered-and-https-on-heroku.html

Rails:Rails - How to Redirect from http://example.com to https://www.example.com

请注意我使用的是Spring MVC 3.1,所以我更喜欢基于WebMvcConfigurerAdapter.addInterceptors(InterceptorRegistry注册表)的解决方案

4 个答案:

答案 0 :(得分:6)

这是一个Servlet过滤器,可将所有非https请求重定向到https:

package com.jamesward;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class HttpsEnforcer implements Filter {

    private FilterConfig filterConfig;

    public static final String X_FORWARDED_PROTO = "x-forwarded-proto";

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        this.filterConfig = filterConfig;
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;

        if (request.getHeader(X_FORWARDED_PROTO) != null) {
            if (request.getHeader(X_FORWARDED_PROTO).indexOf("https") != 0) {
                response.sendRedirect("https://" + request.getServerName() + (request.getPathInfo() == null ? "" : request.getPathInfo()));
                return;
            }
        }

        filterChain.doFilter(request, response);
    }

    @Override
    public void destroy() {
        // nothing
    }
}

我这样做是作为Servlet过滤器,因为我无法获得Spring Interceptor来拦截静态资产(资源)请求。

完整来源:https://github.com/jamesward/springmvc-https-enforcer

答案 1 :(得分:2)

最后回答,但另一种配置驱动的方法是在各种requires-channel="https"标记上使用带有<sec:intercept-url>的Spring Security,并与处理相同代理的Tomcat RemoteIpValve结合使用在前面的答案中提到的标题(x-forwarded-proto等)。阀门根据代理头更改HttpServletRequest.isSecure()的行为,以反映代理报告的协议,而不是连接器实际收到的协议 - 因此任何依赖isSecure()做正确的Spring等框架卸载SSL时,事情会正常运行。

SSL redirects in Heroku有关于配置阀门以便与webapp-runner和Heroku一起使用的说明。

此外,我建议使用PropertyPlaceholderConfigurer让值环境过度。例如,在Spring Security配置中:

<sec:intercept-url pattern="/api/**" requires-channel="${REQUIRES_CHANNEL}" access="..."/>

相关application-config.xml将包含以下内容:

<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
  <property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />
  <property name="properties" ref="applicationProperties"/>
</bean>

<bean id="applicationProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
  <property name="locations">
    <list>
      <value>classpath:/application-config.properties</value>
    </list>
  </property>
</bean>

application-config.properties文件默认包含REQUIRES_CHANNEL=http,然后在部署到Heroku时,设置heroku config:set REQUIRES_CHANNEL=https以覆盖。

答案 2 :(得分:0)

詹姆斯过滤器的优化版本

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class HttpsFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpReq = (HttpServletRequest) request;
        HttpServletResponse httpResp = (HttpServletResponse) response;
        if ("http".equalsIgnoreCase(httpReq.getHeader("x-forwarded-proto"))) {
            StringBuffer requestURL = httpReq.getRequestURL();
            httpResp.sendRedirect("https" + requestURL.substring(requestURL.indexOf(":")));
        } else {
            chain.doFilter(request, response);
        }
    }

    @Override
    public void destroy() {
    }
}

Gist

答案 3 :(得分:-1)

以下是基于spring mvc的解决方案:

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

public class ForceHerokuSsl extends HandlerInterceptorAdapter {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
         String proto = request.getHeader("x-forwarded-proto");
         return proto == null || "https".equalsIgnoreCase(proto);
    }
}

然后在配置中:

@Configuration
@EnableWebMvc
public class WebMvcConfig extends WebMvcConfigurerAdapter {

   public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new ForceHerokuSslInterceptor());
   }
}