【问题标题】:How to enforce HTTPS inside java cedar stack under Heroku如何在 Heroku 下的 java cedar 堆栈中强制执行 HTTPS
【发布时间】:2012-08-07 04:32:55
【问题描述】:

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

这是我找到的链接:

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

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

请注意,我使用的是 Spring MVC 3.1,因此我更喜欢基于 WebMvcConfigurerAdapter.addInterceptors(InterceptorRegistry registry) 的解决方案

【问题讨论】:

    标签: java heroku https


    【解决方案1】:

    詹姆斯过滤器的一点优化版本

    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

    【讨论】:

      【解决方案2】:

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

      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

      【讨论】:

      • request.getPathInfo() 可能会返回“null”,从而生成如下字符串:“yourdomain.comnull”,因此您可能需要在将其附加到重定向 URL 之前对其进行检查
      • 根据 Erik 的评论编辑。我已经为此奋斗了一段时间,答案就在我的眼皮底下!谢谢。
      【解决方案3】:

      这里是基于spring mvc的hte解决方案:

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

      【讨论】:

        【解决方案4】:

        迟到的答案,但另一种配置驱动的方法是在各种 <sec:intercept-url> 标记上使用带有 requires-channel="https" 的 Spring Security,以及处理相同代理标头的 Tomcat RemoteIpValvex-forwarded-proto,等)在先前的答案中提到。 Valve 会根据代理标头更改 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 设置为覆盖。

        【讨论】:

          猜你喜欢
          • 2014-12-16
          • 2012-04-02
          • 2011-12-08
          • 1970-01-01
          • 2011-12-31
          • 2012-07-10
          • 2012-02-14
          • 1970-01-01
          • 2011-12-17
          相关资源
          最近更新 更多