2011-11-03 84 views
6

現在,負載均衡器會處理https,然後將該https傳遞到我的Web服務器。因此,爲每個請求處理https double。我想要完全卸載https,因此我的Web服務器不必處理它。使用Spring Security卸載https到負載均衡器

鑑於Web服務器認爲所有請求都是http,我該如何配置Spring Security和JSP頁面?很明顯,我將不得不修改我的配置中的<intercept-url>元素,使其requires-channel屬性始終爲httpany。在我的JSP頁面中,我必須預先將<c:url value=''/>鏈接預留爲${secureUrl}${nonSecureUrl},具體取決於生成的頁面是否需要爲https或http。需要修改控制器的重定向,就像這樣...還有其他什麼?

似乎非常痛苦,要修改JSP頁面中的所有鏈接以包含方案和主機。有沒有更好的方法來做到這一點?

回答

6

如果終止在負載平衡器SSL那麼你的負載平衡器應發出指示頭原本請求的是什麼協議。例如,F5添加了X-Forwarded-Proto。

從這裏你可以創建自定義ChannelProcessor s看看這個頭,而不是看request.isSecure()。然後您可以繼續使用<intercept-url requires-channel="https">和相關的<c:url>

的步驟:

  1. 子類SecureChannelProcessorInsecureChannelProcessor重寫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()); 
          } 
         } 
        } 
    } 
    
  2. 然後用BeanPostProcessor設置在ChannelDecisionManagerImpl豆這些ChannelProcessors。關於爲什麼/如何爲此使用BeanPostProcessor,請參閱此Spring Security FAQ

+0

試過上述步驟,決定方法沒有被調用,還有什麼我們需要配置? –

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 = '...' 
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; 
} 

}