使用 Spring Security 时,会话超时比预期的要快

Posted

技术标签:

【中文标题】使用 Spring Security 时,会话超时比预期的要快【英文标题】:Session gets timed out sooner than expected when using Spring Security 【发布时间】:2012-08-02 15:38:53 【问题描述】:

我正在使用 Spring Security 3.1,但遇到了会话超时问题。 我在 web.xml 中设置了会话超时,如下所示:

<session-config>
    <session-timeout>
        45
    </session-timeout>
</session-config> 

所以会话应该在 45 分钟后过期。 但是我注意到会话在 2 分钟后 正好 过期!无论我是否在使用应用程序。 这些是我的 Spring Security bean:

<bean id="ConcurrentSessionFilterAdmin" class="org.springframework.security.web.session.ConcurrentSessionFilter">
    <property name="sessionRegistry" ref="sessionRegistry"/>
    <property name="logoutHandlers">
        <list>
            <ref bean = "logoutHandler"/>
        </list>
    </property>
    <property name="expiredUrl" value="/admin/login.jsp?error=expiredURL"/>
</bean>
<bean id="sessionRegistry"
    class="org.springframework.security.core.session.SessionRegistryImpl" autowire="byType" />

<bean id="logoutHandler"
    class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler">
</bean>

<bean id="securityContextPersistenceFilter"
    class="org.springframework.security.web.context.SecurityContextPersistenceFilter">
    <property name="securityContextRepository" ref="securityContextRepository"/>
</bean>

<bean id="securityContextRepository"
    class="org.springframework.security.web.context.HttpSessionSecurityContextRepository">
    <property name="allowSessionCreation" value="false" />
</bean>
<bean id="logoutFilterAdmin"
    class="org.springframework.security.web.authentication.logout.LogoutFilter">
    <constructor-arg value="/admin/login.jsp" />
    <constructor-arg>
        <list>
            <ref bean="logoutHandler"/>
        </list>
    </constructor-arg>
    <property name="filterProcessesUrl" value="/admin/j_spring_security_logout"></property>
</bean>
<bean id="usernamePasswordAuthenticationFilterAdmin"
    class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">
    <property name="usernameParameter" value="j_username"/>
    <property name="passwordParameter" value="j_password"/>
    <property name="allowSessionCreation" value="false"/>
    <property name="authenticationFailureHandler" ref="authenticationFailureHandlerAdmin"/>
    <property name="authenticationManager" ref="authenticationManager"/>
    <property name="authenticationSuccessHandler" ref="authenticationSuccessHandlerAdmin"/>
    <property name="continueChainBeforeSuccessfulAuthentication" value="false"/>
    <property name="filterProcessesUrl" value="/admin/j_spring_security_check"/>
    <property name="sessionAuthenticationStrategy" ref="sessionAuthenticationStrategy"/>
</bean>
<bean id="authenticationFailureHandlerAdmin"
    class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
    <property name="defaultFailureUrl" value="/admin/login.jsp?error=loginfailed" />
</bean>
<bean id="authenticationSuccessHandlerAdmin" 
    class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler">
    <property name="requestCache" ref="requestCache"/>
    <property name="defaultTargetUrl" value="/admin/index.html"/>
</bean>

<bean id="requestCache" class="org.springframework.security.web.savedrequest.HttpSessionRequestCache"/>

<bean id="sessionAuthenticationStrategy"
    class="org.springframework.security.web.authentication.session.ConcurrentSessionControlStrategy">
    <constructor-arg name="sessionRegistry" ref="sessionRegistry" />
    <property name="maximumSessions" value="1" />
    <property name="migrateSessionAttributes" value="true"/>
</bean>

<bean id="basicAuthenticationFilterAdmin"
    class="org.springframework.security.web.authentication.www.BasicAuthenticationFilter">
    <property name="authenticationDetailsSource" ref="authenticationDetailsSource"/>
    <property name="authenticationEntryPoint" ref="authenticationEntryPoint"/>
    <property name="authenticationManager" ref="authenticationManager"/>
</bean>
<bean id="authenticationDetailsSource"
    class="org.springframework.security.authentication.AuthenticationDetailsSourceImpl"/>
<bean id="requestCacheAwareFilter"
    class="org.springframework.security.web.savedrequest.RequestCacheAwareFilter">
    <constructor-arg ref="requestCache"/>
</bean>

<bean id="securityContextHolderAwareRequestFilter"
    class="org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter">
    <property name="rolePrefix" value="ROLE_"/>
</bean>

<bean id="anonymousAuthenticationFilter"
    class="org.springframework.security.web.authentication.AnonymousAuthenticationFilter">
    <constructor-arg value="KEY"/>
</bean>

<bean id="sessionManagementFilterAdmin" class="org.springframework.security.web.session.SessionManagementFilter">
    <constructor-arg ref="securityContextRepository"/>
    <constructor-arg ref="sessionAuthenticationStrategy"/> 
    <property name="authenticationFailureHandler" ref="authenticationFailureHandlerAdmin"/>
    <property name="invalidSessionStrategy" ref="invalidSessionStrategyAdmin"/>
</bean>
<bean id="invalidSessionStrategyAdmin"
    class="org.springframework.security.web.session.SimpleRedirectInvalidSessionStrategy">
    <constructor-arg value="/admin/login.jsp"/>
    <property name="createNewSession" value="false"/>
</bean>
<bean id="exceptionTranslationFilter"
    class="org.springframework.security.web.access.ExceptionTranslationFilter">     
    <property name="authenticationEntryPoint" ref="authenticationEntryPoint" />
    <property name="accessDeniedHandler" ref="accessDeniedHandler" />
    <property name="requestCache" ref="requestCache"/>
</bean>
<bean id="authenticationEntryPoint"
    class="org.springframework.security.web.authentication.Http403ForbiddenEntryPoint">
</bean>
<bean id="accessDeniedHandler"
    class="org.springframework.security.web.access.AccessDeniedHandlerImpl">
</bean>
 <bean id="filterSecurityInterceptorAdmin"
    class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor">
    <property name="authenticationManager" ref="authenticationManager" />
    <property name="accessDecisionManager" ref="accessDecisionManager" />
    <property name="securityMetadataSource" ref="myFilterInvocationSecurityMetadataSource" />
</bean>
<bean id="myFilterInvocationSecurityMetadataSource" class="com.datx.security.model.MyFilterSecurityMetadataSource" autowire="byName" scope="prototype">
</bean>

两分钟后,我被重定向到在第一个 bean 配置中设置的/admin/login.jsp?error=expiredURL。 (这意味着会话已过期) 问题是这些 bean 中的哪一个负责会话过期?我没有设置什么属性导致了这个问题?

【问题讨论】:

我认为问题出在 invalidSessionStrategyAdmin bean 上。 你可以尝试将allowSessionCreation设置为true 以前做过。由于该应用程序完全基于 Restful Web 服务,如果我 [再次] 这样做,我会遇到更多麻烦,因为每个请求都会创建新会话,这会导致“每个请求都有一个登录页面”。 【参考方案1】:

Spring Security 依赖于底层容器,即管理会话超时的容器(请添加有关您正在使用的容器的信息)。但是,我相信如果服务器与 Java EE 兼容,web.xml 设置通常应该具有更高的优先级。

还可以通过调用HttpSession.setMaxInactiveInterval() 方法动态调整单个会话超时,或者可以通过调用invalidate() 使会话无效。

在某些情况下,Spring Security 有可能使 session 失效(例如,在登录后,用户会获得一个新的 HttpSession)。

Spring Security 并发会话控制机制也可能导致会话失效,例如,如果指定了 max-sessions 值。

您可以通过为 org.springframework.security.* 命名空间设置 DEBUG 日志记录级别来检查 Spring Security 何时使会话无效,因为 Spring 通常会将此类信息写入记录器.

【讨论】:

您能否向我解释一下如何启用此调试日志。一个简短的提示可能就足够了。 请参阅reference 的第 1.3.2 节,例如,如果您使用 logback,它将是 %dHH:mm:ss.SSS [%thread] %-5level %logger36 - %msg%n in logback xml 令人惊讶的是你做对了。这是并发会话控制,因为我的同事和我同时登录。谢谢你的帮助。

以上是关于使用 Spring Security 时,会话超时比预期的要快的主要内容,如果未能解决你的问题,请参考以下文章

使用 Spring Security Adapter 时的 Keycloak 会话超时行为

使用 Spring Security saml 的 IDP 会话超时

Spring Security - 会话超时而不扩展/更新

SAML Spring Security 会话超时

Spring Boot,Spring Security,会话范围 Bean 的会话超时问题,@PreDestroy

具有自定义会话超时的 Spring Security [关闭]