如果标题不够清楚,我很抱歉。这是详细信息。
背景
我正在开发使用 Spring 3.1.1 和 Spring security 3.1.0 的基于 Spring 的应用程序。这是我们描述符的相关片段:
<security:http auto-config='true'>
<security:intercept-url pattern="/login.jsp*" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<security:intercept-url pattern="/login*" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<security:intercept-url pattern="/**" access="ROLE_USER" />
<security:form-login login-page='/login' authentication-failure-url="/login?authfailed=true"/>
</security:http>
网页上的“退出”链接指的是 URL,如ROOT-URL/j_spring_security_logout
. 因此,单击此 URL 会将我们带到登录页面 ( login.jsp
),并且可以再次成功登录。
问题
如果用户登录到应用程序,等到会话过期,然后尝试注销他到达登录页面。这可以。然后他输入正确的凭据并单击登录按钮。现在他被重定向到相同的登录页面,其中用户名和密码字段为空,而不是进入应用程序。第二次尝试登录成功。
重要提示:仅当用户之前登录、会话已过期并且他尝试注销时才会发生这种情况。例如,如果用户在会话到期后单击任何其他链接,则不会发生这种情况。在这种情况下,他会被重定向到登录页面,并且可以从第一次尝试成功登录。
分析
我的调查显示如下。由于 HTTP 重定向导致我们两次到达登录页面,SavedRequestAwareAuthenticationSuccessHandler.onAuthenticationSuccess()
并且因为requestCache
包含对登录页面的请求而发生。是在会话属性中存储“缓存”请求requestCache
的类型变量。HttpSessionRequestCache
"SPRING_SECURITY_SAVED_REQUEST"
在正常情况下,此缓存用于重定向到未经身份验证的用户在其身份验证后请求的页面。
但这就是我们的案例中发生的情况。用户登录。然后他的会话过期了。然后他点击链接退出。由于会话已过期,用户被重定向到“j_spring_security_logout”,将他重定向到登录页面。
在这种方式的某个地方,登录 URL 被缓存为“请求的”,因此当用户登录时,他被重定向到请求的 URL,即登录页面。当重定向发生时,缓存的 URL 被删除,因此不会发生无限循环;第二次尝试登录成功。
以下是相关代码参考:
ExceptionTranslationFilter.handleSpringSecurityException()
调用sendStartAuthentication()
(第 168 行)
执行以下操作(第 183-184 行):
SecurityContextHolder.getContext().setAuthentication(null);
requestCache.saveRequest(request, response);
但是此时请求的 URL 是登录页面。因此,登录页面被缓存。
看起来此时saveRequest()
不应调用 just ,例如,这闻起来是 Spring 框架中的错误...
我有这个问题的解决方案,我会在这里发布。但是我的解决方案对我来说看起来像是一个补丁,所以我希望有人知道“正确”的解决方案。
提前致谢。