我发现很多关于在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注册表)的解决方案
答案 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来拦截静态资产(资源)请求。
答案 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() {
}
}
答案 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());
}
}