2015-09-30 215 views
1

我的公司Intranet应用程序使用预认证方案。它在SpringSecurity过滤器链之前插入了两个过滤器。第一种是公司提供的过滤器。它处理所有登录,密码等,如果它识别用户,则将身份验证数据放入Cookie中的Principal中。第二个翻译所有这些,创建UserDetails对象和一个身份验证令牌并将其放置在SecurityContextHolder中。SpringSecurity为什么不把我的SecurityContext放在HttpSession中?

SecurityContextHolder.getContext().setAuthentication(token); 
logger.debug("Auth token submitted"); 

我的日志证实,这种情况正在发生:

2015-09-30 13:02:08,998 DEBUG c.a.v.c.s.MyPreauthFilter [http-bio-8081-exec-63] Auth token submitted 

数毫秒后,Spring Security的过滤器链进来并执行以下操作:

2015-09-30 13:02:09,002 DEBUG o.s.s.w.FilterChainProxy [http-bio-8081-exec-63] /index.html at position 1 of 11 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter' 
2015-09-30 13:02:09,007 DEBUG o.s.s.w.FilterChainProxy [http-bio-8081-exec-63] /index.html at position 2 of 11 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter' 
2015-09-30 13:02:09,008 DEBUG o.s.s.w.c.HttpSessionSecurityContextRepository [http-bio-8081-exec-63] HttpSession returned null object for SPRING_SECURITY_CONTEXT 
2015-09-30 13:02:09,008 DEBUG o.s.s.w.c.HttpSessionSecurityContextRepository [http-bio-8081-exec-63] No SecurityContext was available from the HttpSession: [email protected] A new one will be created. 

基本上,HttpSessionSecurityContextRespositorySecurityContextPersistenceFilter(过滤链的一部分)调用,并检查SESSION中的安全上下文,在会话中找不到一个,并替换上下文I只是放置在SecurityContextHolder中,一个新的空的,导致下面几行认证失败。

2015-09-30 13:02:09,024 DEBUG o.s.s.w.a.ExceptionTranslationFilter [http-bio-8081-exec-63] Access is denied (user is anonymous); redirecting to authentication entry point 
org.springframework.security.access.AccessDeniedException: Access is denied 

由于春节文档不提HttpSessionSecurityContextRespository,我想我可能是不应该乱用那个。

相反,我想也许我可以尝试在Spring Security Filter链后插入第二个过滤器,但这并没有帮助。 FilterSecurityInterceptor(链中的第11项)拒绝对我进行身份验证,就像我的第二个筛选器位于链中之前那样。

什么会保存会话中的SecurityContext,以及如何在清除刚刚设置的安全上下文时打败SecurityContextPersistenceFilter的行为?

回答

0

我开发了一个解决方法。它不应该是必要的,但它似乎工作。

@Override 
public void doFilter(ServletRequest request, ServletResponse response, 
     FilterChain chain) throws IOException, ServletException 
{ 

... 
    PreAuthenticatedAuthenticationToken token = ... 


    logger.debug("Auth token placed in SecurityContext: \n" + token); 
    SecurityContextHolder.getContext().setAuthentication(token); 

    // make sure the session has a SecurityContext at this point 
    ensureSessionHasSecurityContext(hreq); 

    super.doFilter(request,response, chain); 

    logger.debug("Auth token after rest of chain: \n" + SecurityContextHolder.getContext() 
      .getAuthentication()); 

} 

private void ensureSessionHasSecurityContext(HttpServletRequest hreq) { 
    HttpSession session = hreq.getSession(false); 
    Object securityContext = session.getAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY); 
    if (securityContext == null) { 
     logger.debug("no SecurityContext found in session, inserting ours"); 
     session.setAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY, SecurityContextHolder.getContext()); 
    } 

} 

请对这个解决方案进行讨论,如果它出现问题。但这是我能想到的唯一方法,以确保筛选器链在我的预认证过滤器完成其工作之后,但在Spring Filter Chain接管之前不会影响我的新认证。

相关问题