2

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

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: org.apache.catalina.session.StandardSessionFacade@721c23ce. A new one will be created.

基本上,HttpSessionSecurityContextRespositorySecurityContextPersistenceFilter(过滤器链的一部分)调用并检查 SESSION 的安全上下文,在会话中找不到一个,并将我刚刚放在 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

由于 Spring 文档没有提到HttpSessionSecurityContextRespository,我想我可能不应该对此感到困惑。

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

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

4

1 回答 1

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

}

如果它对您有问题,请揭穿此解决方案。但这是我能想到的确保过滤器链不会破坏我的新身份验证的唯一方法,在我希望它的时候,就在我的 preauth 过滤器完成其工作之后,但在 Spring 过滤器链接管之前。

于 2015-10-01T02:52:31.967 回答