为什么匿名用户被Spring Security重定向到expiredsessionurl

LWK*_*K69 5 spring-security

我真的想了解Spring Security是如何工作的,但此刻我有点失落.这是一个简单的场景:

  1. 用户访问网站主页但未登录
  2. SecurityContextPersistenceFilter 记录没有SecurityContext可用,将创建一个新的
  3. AnonymousAuthenticationFilter 使用匿名标记填充SecurityContextHolder
  4. 创建一个ID = C2A35ED5A41E29865FF53162B0024D52的会话
  5. 用户让页面处于空闲状态,直到会话超时
  6. 用户点击"关于"页面(或主页)
  7. SecurityContextPersistenceFilter 再次记录没有SecurityContext可用,并将创建一个新的
  8. AnonymousAuthenticationFilter 再次使用匿名标记填充SecurityContextHolder
  9. SessionManagementFilter 请求会话ID为C2A35ED5A41E29865FF53162B0024D52的日志无效
  10. SessionManagementFilter 记录它正在开始一个新会话并重定向到/ invalidsession

这些页面配置为.authorizeRequests().antMatchers("/","/home","/about").permitAll(). 我打开了无效会话选项以处理经过身份验证的用户:.sessionManagement().invalidSessionUrl("/errors/invalidSession").如果我注释掉该选项,那么上面描述的所有内容都与步骤#10完全相同 - SessionManagementFilter看到所请求的会话ID无效(#9)但不启动新会话并执行重定向(#10).

为什么?如何保持无效会话选项但正确处理匿名用户,即不重定向?或者这是不可能的,我将不得不单独处理经过身份验证的用户?如果有人能帮助我理解这里发生的事情并指出我解决这个问题的方向,我将非常感激.如果您需要查看我的完整http配置,请告诉我.

编辑

我与匿名和注册(经过身份验证)的用户进行了一系列测试.如果 .sessionManagement().invalidSessionUrl("/errors/invalidSession")启用,则两种类型的用户最终都会到达错误页面.未选中RememberMe的经过身份验证的用户与匿名用户相同.如果选中了RememberMe,则在RememberMe超时后会出现错误页面.

如果我禁用无效会话选项,则没有用户获得错误页面(这是有意义的).两种类型的用户都可以浏览公共页面,只要他们想要,并且会话或RememberMe过期后将要求经过身份验证的用户登录.

如果您对此处涉及的代码感兴趣,请参阅 SessionManagementFilter

if (invalidSessionStrategy != null) {
    invalidSessionStrategy
        .onInvalidSessionDetected(request, response);
    return;
}
Run Code Online (Sandbox Code Playgroud)

如果.sessionManagement().invalidSessionUrl启用,SimpleRedirectInvalidSessionStrategy则调用默认方法,该方法执行以下代码:

if (createNewSession) {
    request.getSession();
}
redirectStrategy.sendRedirect(request, response, destinationUrl);
Run Code Online (Sandbox Code Playgroud)

createNewSession布尔可设置通过setCreateNewSession(boolean createNewSession),其被描述为:

确定是否应在重定向之前创建新会话(以避免可能的循环问题,其中使用重定向的请求发送相同的会话ID).或者,确保配置的URL不通过SessionManagementFilter.

所以,在我看来,它.sessionManagement().invalidSessionUrl最适合所有页面都经过身份验证的网站.我正在查看的选项是在SessionManagementFilter检查页面访问权限之前放置的自定义过滤器,并根据需要打开/关闭"createNewSession"或关闭无效会话选项并在其他地方处理经过身份验证的页面(?).我也偶然发现<%@ page session=“false” %>了这个问题 - 为什么要设置JSP页面session ="false"指令? - 我将进一步研究.对Spring Security这么新,我对正确处理这种情况没有很好的理解.任何帮助,将不胜感激.

LWK*_*K69 2

好的,过去几周我一直在研究 Spring Security,试图了解它们是如何组合在一起的。我仍在学习,但对于这种特殊情况,我发现了两种有效的方法。

最明显的就是绕过公共页面的安全性,如下所示:

@Override
public void configure(WebSecurity web) throws Exception
{
    web
    .ignoring()
        .antMatchers("/", "/home", "/about", "/login**", "/thankyou", "/user/signup**", "/resources/**")
    ;
}
Run Code Online (Sandbox Code Playgroud)

我仍然对网络安全了解不够,不知道这是否是可接受的方法,但它允许匿名用户浏览网站而不会收到无效会话错误。

更难的解决方案(对于像我这样的 Java 和 Spring 菜鸟来说)是基于这些 SO 问题:

Spring Security 无效会话重定向

如何在 Spring Security 中设置自定义无效会话策略

默认SimpleRedirectInvalidSessionStrategyfinal意味着我必须基本上创建该类的副本(不确定这是一个多么好的主意)。您不能使用会话属性,因为会话在达到此策略时已被销毁,因此我为会话 cookie 创建了一个名为 authUser 的帮助程序类(如果有人想查看它,我可以发布该类)。cookie 在LoginSuccessHandler或中创建或更新RememberMeSuccessHandler,它指示用户是匿名还是经过身份验证:

authCookie.setCookie(request, response, "anonymousUser");
or
authCookie.setCookie(request, response, authentication.getName());
Run Code Online (Sandbox Code Playgroud)

我目前仅将实际登录用于测试目的 - 它最终只是某种简单的是/否指示器。 CustomLogoutSuccessHandler将其重置为匿名用户

无效的会话方法如下所示:

@Override
public void onInvalidSessionDetected(HttpServletRequest request, HttpServletResponse response) 
    throws IOException, ServletException {

    String url = destinationUrl;

    //reset context default value
    redirectStrategy.setContextRelative(false);

    if (authCookie.isCurrentCookieAnonymous()) {
        //pass the URL originally requested by the anonymous user
        url = request.getRequestURI();
        //the URL needs to have the context removed
        redirectStrategy.setContextRelative(true);
    }

    //always revert to anonymous user
    authCookie.setCookie(request, response, "anonymousUser");

    logger.debug("Starting new session (if required) and redirecting to '" + url + "'");

    if (createNewSession)
        request.getSession();

    redirectStrategy.sendRedirect(request, response, url);
}
Run Code Online (Sandbox Code Playgroud)

同样,如果需要,我可以发布完整的课程。

该类SecurityConfig包括以下内容:

@Bean
public SessionManagementBeanPostProcessor sessionManagementBeanPostProcessor() {
    return new SessionManagementBeanPostProcessor();
}

protected static class SessionManagementBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) {
        if (bean instanceof SessionManagementFilter) {
            SessionManagementFilter filter = (SessionManagementFilter) bean;
            filter.setInvalidSessionStrategy(new RedirectInvalidSession("/errors/invalidSession"));
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
        return bean;
    }
}
Run Code Online (Sandbox Code Playgroud)

到目前为止,我的测试对于匿名用户和经过身份验证的用户都是成功的,但这种方法尚未经过生产测试。


归档时间:

查看次数:

1529 次

最近记录:

10 年,1 月 前