Spring security 如何使用Spring Security绕过匿名用户的会话超时?

Spring security 如何使用Spring Security绕过匿名用户的会话超时?,spring-security,Spring Security,我已经与SpringSecurity合作两周了,除了匿名用户和会话超时之外,它工作得很好 用例#1 匿名用户可以访问该网站并查看公共页面(/home、/about、/signup等),只要他们愿意(无会话超时) 如果用户选择受保护的页面,则会出现登录屏幕 用例2 注册用户登录并可以查看受保护的页面 如果会话超时,将显示invalidSessionUrl页面,并指示用户登录 我已经阅读了大量的SO和博客文章,但我似乎找不到用例1的解决方案。我正在使用Spring4.1.6.RELEASE、Spri

我已经与SpringSecurity合作两周了,除了匿名用户和会话超时之外,它工作得很好

用例#1

  • 匿名用户可以访问该网站并查看公共页面(/home、/about、/signup等),只要他们愿意(无会话超时)
  • 如果用户选择受保护的页面,则会出现登录屏幕
  • 用例2

  • 注册用户登录并可以查看受保护的页面

  • 如果会话超时,将显示invalidSessionUrl页面,并指示用户登录

  • 我已经阅读了大量的SO和博客文章,但我似乎找不到用例1的解决方案。我正在使用Spring4.1.6.RELEASE、SpringSecurity4.0.2 RELEASE和Tomcat8

    这是我的安全配置:

        protected void configure(HttpSecurity http) throws Exception {
        http
        .authorizeRequests()
            .antMatchers("/", "/home", "/about", "/login**", "/thankyou", "/user/signup**", "/errors/**").permitAll() 
            .regexMatchers("/user/signup/.*").permitAll()
            .antMatchers("/recipe/listRecipes*").hasAuthority("GUEST")
            .antMatchers("/recipe/addRecipe*").hasAuthority("AUTHOR")
            .antMatchers("/admin/**").hasAuthority("ADMIN")
            .anyRequest().authenticated()
            .expressionHandler(secExpressionHandler())
            .and()
        .formLogin()
            .loginPage("/login")
            .failureUrl("/login?err=1")
            .permitAll()
            .and()
        .logout()
            .logoutSuccessUrl("/thankyou")
            .deleteCookies( "JSESSIONID" )
            .invalidateHttpSession(false)
            .and()
        .exceptionHandling()
            .accessDeniedPage("/errors/403")
            .and()
        .rememberMe()
            .key("recipeOrganizer")
            .tokenRepository(persistentTokenRepository())
            .tokenValiditySeconds(960)      //.tokenValiditySeconds(1209600)
            .rememberMeParameter("rememberMe");
    
        http
        .sessionManagement()
            .sessionAuthenticationErrorUrl("/errors/402")   
            .invalidSessionUrl("/errors/invalidSession")
            .maximumSessions(1)
            .maxSessionsPreventsLogin(true)
            .expiredUrl("/errors/expiredSession")
            .and()
            .sessionFixation().migrateSession();
    
    会话过期后匿名用户的任何操作都会导致无效的会话异常。问题在于安全筛选器链(请参见下面的日志)
    匿名身份验证筛选器(#11)创建新会话,但
    会话管理筛选器(#12)检索先前过期的会话,将其与新会话进行比较,并抛出
    invalidsession
    异常。我希望这种情况发生在登录用户身上,而不是匿名用户身上。但是,在抛出异常时,安全上下文已被破坏,因此我无法知道之前的会话是来自匿名用户还是登录用户

    我考虑过的解决方案有:

  • 将全局会话超时设置为24小时或更长时间,然后在LoginSuccessHandler和RemembermSuccessHandler中调整注册用户的超时
  • 关闭公共页面的安全性
  • 创建一个单独的cookie以指示用户类型(anon与登录),并在InvalidSessionStrategy中查询该cookie以将anon用户重定向到/主页
  • 创建一个自定义筛选器,首先执行该筛选器以标识一个非用户(可能吗?),并简单地扩展当前会话
  • 编写一些javascript或jquery来定期检查会话超时并为其他用户重置它
  • 解决方案#1可能会导致服务器上的过期会话出现问题(不确定这是否是一个大问题)#我觉得2不合适,尤其是当公共页面可能包含有关登录用户的任何信息时#3可能会起作用,但另一个用户可以单击除主页以外的公共链接,但会被重定向到主页,因为我认为在InvalidSessionStrategy中没有办法知道他们试图访问哪个链接?我不确定#4是否有效——我还没有尝试过#5也可以工作,但它会增加网络流量

    我希望有人能给我指出一个切实可行的解决办法。这一定是很多网站都在处理的事情,但我正在兜圈子,试图解决这个问题。提前感谢您的任何建议或提示

    下面是日志的一部分来说明发生了什么。出于测试目的,我将会话超时设置为60秒

    Initial access to website
    20:49:29.823 DEBUG: org.springframework.security.web.FilterChainProxy - / at position 11 of 14 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
    20:49:29.839 DEBUG: org.springframework.security.web.authentication.AnonymousAuthenticationFilter - Populated SecurityContextHolder with anonymous token: 'org.springframework.security.authentication.AnonymousAuthenticationToken@9055c2bc: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: null; Granted Authorities: ROLE_ANONYMOUS'
    20:49:29.839 DEBUG: org.springframework.security.web.FilterChainProxy - / at position 12 of 14 in additional filter chain; firing Filter: 'SessionManagementFilter'
    20:49:29.839 DEBUG: org.springframework.security.web.FilterChainProxy - / at position 13 of 14 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
    20:49:29.839 DEBUG: org.springframework.security.web.FilterChainProxy - / at position 14 of 14 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
    20:49:29.839 DEBUG: org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/'; against '/'
    20:49:29.839 DEBUG: org.springframework.security.web.access.intercept.FilterSecurityInterceptor - Secure object: FilterInvocation: URL: /; Attributes: [permitAll]
    20:49:29.854 DEBUG: org.springframework.security.web.access.intercept.FilterSecurityInterceptor - Previously Authenticated: org.springframework.security.authentication.AnonymousAuthenticationToken@9055c2bc: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: null; Granted Authorities: ROLE_ANONYMOUS
    20:49:29.871 DEBUG: org.springframework.security.access.vote.AffirmativeBased - Voter: org.springframework.security.web.access.expression.WebExpressionVoter@ff577, returned: 1
    20:49:29.871 DEBUG: org.springframework.security.web.access.intercept.FilterSecurityInterceptor - Authorization successful
    20:49:30.136 DEBUG: net.mycompany.myapp.config.SessionListener - AuthenticationSuccess - principal: anonymousUser
    20:49:30.167 DEBUG: net.mycompany.myapp.config.SessionListener - AuthenticationSuccess - authority contains: ROLE_ANONYMOUS
    20:49:30.167 INFO : net.mycompany.myapp.config.SessionListener - sessionCreated: Session created on: Mon Sep 21 20:49:30 CDT 2015
    20:49:30.167 INFO : net.mycompany.myapp.config.SessionListener - sessionCreated: Session last accessed on: Mon Sep 21 20:49:30 CDT 2015
    20:49:30.167 INFO : net.mycompany.myapp.config.SessionListener - sessionCreated: Session expires after: 60 seconds
    20:49:30.167 INFO : net.mycompany.myapp.config.SessionListener - sessionCreated: Session ID: CA34FE74B56B8EF94181B1231A7D4FF6
    
    Session times out after 60 seconds
    20:50:46.015 INFO : net.mycompany.myapp.config.SessionDestroyedListener - destroyedEvent
    20:50:46.015 INFO : net.mycompany.myapp.config.SessionDestroyedListener - object:org.springframework.security.web.session.HttpSessionDestroyedEvent[source=org.apache.catalina.session.StandardSessionFacade@17827f3e]
    20:50:46.015 INFO : net.mycompany.myapp.config.SessionListener - sessionDestroyed: Session created on: Mon Sep 21 20:49:30 CDT 2015
    20:50:46.015 INFO : net.mycompany.myapp.config.SessionListener - sessionDestroyed: Session last accessed on: Mon Sep 21 20:49:32 CDT 2015
    20:50:46.015 INFO : net.mycompany.myapp.config.SessionListener - sessionDestroyed: Session expires after: 60 seconds
    20:50:46.015 INFO : net.mycompany.myapp.config.SessionListener - sessionDestroyed: Session ID: CA34FE74B56B8EF94181B1231A7D4FF6
    
    Click on "/home" link (unsecured)
    20:50:53.927 DEBUG: org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/home'; against '/resources/**'
    20:50:53.927 DEBUG: org.springframework.security.web.FilterChainProxy - /home at position 1 of 14 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
    20:50:53.927 DEBUG: org.springframework.security.web.FilterChainProxy - /home at position 2 of 14 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
    20:50:53.927 DEBUG: org.springframework.security.web.context.HttpSessionSecurityContextRepository - No HttpSession currently exists
    20:50:53.927 DEBUG: org.springframework.security.web.context.HttpSessionSecurityContextRepository - No SecurityContext was available from the HttpSession: null. A new one will be created.
    20:50:53.927 DEBUG: org.springframework.security.web.FilterChainProxy - /home at position 3 of 14 in additional filter chain; firing Filter: 'HeaderWriterFilter'
    20:50:53.927 DEBUG: org.springframework.security.web.header.writers.HstsHeaderWriter - Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@4c668dec
    20:50:53.927 DEBUG: org.springframework.security.web.FilterChainProxy - /home at position 4 of 14 in additional filter chain; firing Filter: 'CsrfFilter'
    20:50:53.927 DEBUG: org.springframework.security.web.FilterChainProxy - /home at position 5 of 14 in additional filter chain; firing Filter: 'LogoutFilter'
    20:50:53.927 DEBUG: org.springframework.security.web.util.matcher.AntPathRequestMatcher - Request 'GET /home' doesn't match 'POST /logout
    20:50:53.927 DEBUG: org.springframework.security.web.FilterChainProxy - /home at position 6 of 14 in additional filter chain; firing Filter: 'UsernamePasswordAuthenticationFilter'
    20:50:53.927 DEBUG: org.springframework.security.web.util.matcher.AntPathRequestMatcher - Request 'GET /home' doesn't match 'POST /login
    20:50:53.927 DEBUG: org.springframework.security.web.FilterChainProxy - /home at position 7 of 14 in additional filter chain; firing Filter: 'ConcurrentSessionFilter'
    20:50:53.927 DEBUG: org.springframework.security.web.FilterChainProxy - /home at position 8 of 14 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
    20:50:53.927 DEBUG: org.springframework.security.web.FilterChainProxy - /home at position 9 of 14 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
    20:50:53.927 DEBUG: org.springframework.security.web.FilterChainProxy - /home at position 10 of 14 in additional filter chain; firing Filter: 'RememberMeAuthenticationFilter'
    20:50:53.927 DEBUG: org.springframework.security.web.FilterChainProxy - /home at position 11 of 14 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
    20:50:53.927 DEBUG: org.springframework.security.web.authentication.AnonymousAuthenticationFilter - Populated SecurityContextHolder with anonymous token: 'org.springframework.security.authentication.AnonymousAuthenticationToken@9055c2bc: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: null; Granted Authorities: ROLE_ANONYMOUS'
    20:50:53.927 DEBUG: org.springframework.security.web.FilterChainProxy - /home at position 12 of 14 in additional filter chain; firing Filter: 'SessionManagementFilter'
    20:50:53.927 DEBUG: org.springframework.security.web.session.SessionManagementFilter - Requested session ID CA34FE74B56B8EF94181B1231A7D4FF6 is invalid.
    20:50:53.927 DEBUG: org.springframework.security.web.session.SimpleRedirectInvalidSessionStrategy - Starting new session (if required) and redirecting to '/errors/invalidSession'
    20:50:53.927 DEBUG: net.mycompany.myapp.config.SessionListener - AuthenticationSuccess - principal: anonymousUser
    20:50:53.927 DEBUG: net.mycompany.myapp.config.SessionListener - AuthenticationSuccess - authority contains: ROLE_ANONYMOUS
    20:50:53.927 INFO : net.mycompany.myapp.config.SessionListener - sessionCreated: Session created on: Mon Sep 21 20:50:53 CDT 2015
    20:50:53.927 INFO : net.mycompany.myapp.config.SessionListener - sessionCreated: Session last accessed on: Mon Sep 21 20:50:53 CDT 2015
    20:50:53.942 INFO : net.mycompany.myapp.config.SessionListener - sessionCreated: Session expires after: 60 seconds
    20:50:53.942 INFO : net.mycompany.myapp.config.SessionListener - sessionCreated: Session ID: 6F7FD6230BC075B7768648BBBC08E3F4
    20:50:53.942 DEBUG: org.springframework.security.web.session.HttpSessionEventPublisher - Publishing event: org.springframework.security.web.session.HttpSessionCreatedEvent[source=org.apache.catalina.session.StandardSessionFacade@412cbe09]
    20:50:53.942 DEBUG: org.springframework.security.web.DefaultRedirectStrategy - Redirecting to '/myapp/errors/invalidSession'
    

    几天后,我发布了一个类似的问题:,我已经发布了答案。上述解决方案#2可行,但我不喜欢关闭所有安全性,即使是公共页面。我最终实现的是3和4的组合。有关完整答案,请参见链接问题