Spring Security版本:2.0.5
应用场景:
用户登录系统,进行录入操作,长时间未保存,当会话超时后,用户进行保存(通过AJAX请求),系统提示“会话超时请重新登录”。
Spring Security目前的行为:
Spring Security实际上是把这种请求当成未登录的请求,并抛出不允许访问的异常(org.springframework.security.AccessDeniedException),然后请求重定向到登录页面。
相关的方法有:
org.springframework.security.ui.ExceptionTranslationFilter.doFilterHttp(HttpServletRequest, HttpServletResponse, FilterChain)
org.springframework.security.ui.ExceptionTranslationFilter.handleException(ServletRequest, ServletResponse, FilterChain, SpringSecurityException)
org.springframework.security.ui.ExceptionTranslationFilter.sendStartAuthentication(ServletRequest, ServletResponse, FilterChain, AuthenticationException)
org.springframework.security.ui.webapp.AuthenticationProcessingFilterEntryPoint.commence(ServletRequest, ServletResponse, AuthenticationException)
见org.springframework.security.ui.ExceptionTranslationFilter.handleException(ServletRequest, ServletResponse, FilterChain, SpringSecurityException)中:
if (exception instanceof AuthenticationException) {
if (logger.isDebugEnabled()) {
logger.debug("Authentication exception occurred; redirecting to authentication entry point", exception);
}
sendStartAuthentication(request, response, chain, (AuthenticationException) exception);
}
else if (exception instanceof AccessDeniedException) {
if (authenticationTrustResolver.isAnonymous(SecurityContextHolder.getContext().getAuthentication())) {
if (logger.isDebugEnabled()) {
logger.debug("Access is denied (user is anonymous); redirecting to authentication entry point", exception);
}
sendStartAuthentication(request, response, chain, new InsufficientAuthenticationException("Full authentication is required to access this resource"));//在这里重定向到登录页面
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Access is denied (user is not anonymous); delegating to AccessDeniedHandler", exception);
}
accessDeniedHandler.handle(request, response, (AccessDeniedException) exception);
}
}
正常来说应该要重写org.springframework.security.ui.ExceptionTranslationFilter.handleException方法,加入相应的逻辑(判断是否为AJAX请求并作出对应的处理),但由于handleException为私有方法,不能直接对其进行扩展,所以只能寻找其它扩展方式了。
可以选择重写org.springframework.security.ui.webapp.AuthenticationProcessingFilterEntryPoint.commence,这个方法的作用是执行重定向到登录页面,我们可以简单的认为当请求为AJAX时即是会话超时的场景,当然再严谨一点,比如异常的类型与消息,代码如下:
public void commence(ServletRequest request, ServletResponse response,
AuthenticationException authException) throws IOException,
ServletException {
HttpServletRequest httpRequest = (HttpServletRequest)request;
if ("XMLHttpRequest".equals(httpRequest.getHeader("X-Requested-With"))){
Map<String, Object> error = new HashMap<String, Object>();
error.put("success", false);
error.put("code", "001");
error.put("message", "与服务器的会话已经超时");
error.put("data", ""); // 兼容extjs form loading
RenderUtils.renderJSON((HttpServletResponse)response, error);
} else
super.commence(request, response, authException);
}
...
<http entry-point-ref="authenticationProcessingFilterEntryPoint">
...