现在,负载均衡器处理https,然后将该https传递给我的Web服务器。因此,为每个请求处理https double。我想要做的是完全卸载https,这样我的网络服务器就不必处理它了。
如果Web服务器认为所有请求都是http,我如何配置Spring Security和JSP页面?显然,我必须修改配置的<intercept-url>
元素,使其requires-channel
属性始终为http
或any
。在我的JSP页面中,我必须在<c:url value=''/>
和${secureUrl}
之前添加${nonSecureUrl}
个链接,具体取决于结果页面是否需要为https或http。控制器的重定向也需要像这样修改......还有别的吗?
修改JSP页面中的所有链接以包含方案和主机似乎非常痛苦。有没有更好的方法呢?
答案 0 :(得分:6)
如果您在负载均衡器处终止SSL,则负载均衡器应发送一个标头,指示最初请求的协议。例如,F5添加了X-Forwarded-Proto。
从这里,您可以创建自定义ChannelProcessor
来查看此标题,而不是查看request.isSecure()
。然后,您可以继续使用<intercept-url requires-channel="https">
和相对<c:url>
。
步骤:
子类SecureChannelProcessor和InsecureChannelProcessor覆盖decide()
。在decide()
中检查负载均衡器发送的标头。
@Override
public void decide(FilterInvocation invocation, Collection<ConfigAttribute> config) throws IOException, ServletException {
for (ConfigAttribute attribute : config) {
if (supports(attribute)) {
if (invocation.getHttpRequest().
getHeader("X-Forwarded-Proto").equals("http")) {
entryPoint.commence(invocation.getRequest(),
invocation.getResponse());
}
}
}
}
然后使用BeanPostProcessor
在ChannelDecisionManagerImpl bean上设置这些ChannelProcessors。请参阅此Spring Security FAQ,了解为何/如何使用BeanPostProcessor
。
答案 1 :(得分:2)
要完成伟大的sourcedelica答案,请输入完整代码:
对于第1步:
@Component
public class SecureChannelProcessorHack extends SecureChannelProcessor {
@Override
public void decide(FilterInvocation invocation, Collection<ConfigAttribute> config) throws IOException, ServletException {
for (ConfigAttribute attribute : config) {
if (supports(attribute)) {
if ("http".equals(invocation.getHttpRequest().getHeader("X-Forwarded-Proto"))) {
getEntryPoint().commence(invocation.getRequest(),
invocation.getResponse());
}
}
}
}
}
@Component
public class InsecureChannelProcessorHack extends InsecureChannelProcessor {
@Override
public void decide(FilterInvocation invocation, Collection<ConfigAttribute> config) throws IOException, ServletException {
for (ConfigAttribute attribute : config) {
if (supports(attribute)) {
if ("https".equals(invocation.getHttpRequest().getHeader("X-Forwarded-Proto"))) {
getEntryPoint().commence(invocation.getRequest(),
invocation.getResponse());
}
}
}
}
}
第2步:
@Configuration
public class LoadBalancerHack implements BeanPostProcessor {
@Inject
SecureChannelProcessorHack secureChannelProcessorHack;
@Inject
InsecureChannelProcessorHack insecureChannelProcessorHack;
@Value("${behind.loadbalancer?false}")
boolean behindLoadBalancer;
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (behindLoadBalancer && bean instanceof ChannelDecisionManagerImpl) {
System.out.println("********* Post-processing " + beanName);
((ChannelDecisionManagerImpl) bean).setChannelProcessors(newArrayList(
insecureChannelProcessorHack,
secureChannelProcessorHack
));
}
return bean;
}
}
答案 2 :(得分:1)
看起来Grails支持这个作为安全插件的一部分。查看http://grails-plugins.github.com/grails-spring-security-core/docs/manual/guide/17%20Channel%20Security.html的底部,他们谈论检查请求标题,LB将设置。
grails.plugins.springsecurity.secureChannel.useHeaderCheckChannelSecurity = true
grails.plugins.springsecurity.secureChannel.secureHeaderName = '...'
grails.plugins.springsecurity.secureChannel.secureHeaderValue = '...'
grails.plugins.springsecurity.secureChannel.insecureHeaderName = '...'
grails.plugins.springsecurity.secureChannel.insecureHeaderValue = '...'