这个问题有点老了,但答案总是有用的。
首先,这是会话支持的 CSRF 令牌的一个已知问题,如文档中所述:CSRF Caveats - Timeouts。
要解决这个问题,请使用一些 Javascript 来检测即将发生的超时,使用与会话无关的 CSRF 令牌存储库或创建自定义 AccessDeniedHandler 路由。我选择了后者:
配置 XML:
<http>
<!-- ... -->
<access-denied-handler ref="myAccessDeniedHandler"/>
</http>
<bean id="myAccessDeniedHandler" class="package.MyAccessDeniedHandler">
<!-- <constructor-arg ref="myInvalidSessionStrategy" /> -->
</bean>
MyAccessDeniedHandler:
public class MyAccessDeniedHandler implements AccessDeniedHandler {
/* ... */
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException exception)
throws IOException, ServletException {
if (exception instanceof MissingCsrfTokenException) {
/* Handle as a session timeout (redirect, etc).
Even better if you inject the InvalidSessionStrategy
used by your SessionManagementFilter, like this:
invalidSessionStrategy.onInvalidSessionDetected(request, response);
*/
} else {
/* Redirect to a error page, send HTTP 403, etc. */
}
}
}
或者,您可以将自定义处理程序定义为DelegatingAccessDeniedHandler:
<bean id="myAccessDeniedHandler" class="org.springframework.security.web.access.DelegatingAccessDeniedHandler">
<constructor-arg name="handlers">
<map>
<entry key="org.springframework.security.web.csrf.MissingCsrfTokenException">
<bean class="org.springframework.security.web.session.InvalidSessionAccessDeniedHandler">
<constructor-arg name="invalidSessionStrategy" ref="myInvalidSessionStrategy" />
</bean>
</entry>
</map>
</constructor-arg>
<constructor-arg name="defaultHandler">
<bean class="org.springframework.security.web.access.AccessDeniedHandlerImpl">
<property name="errorPage" value="/my_error_page"/>
</bean>
</constructor-arg>
</bean>