Spring Security会话超时AJAX处理

SpringSecurity版本:2.0.5

应用场景:

用户登录系统,进行录入操作,长时间未保存,当会话超时后,用户进行保存(通过AJAX请求),系统提示“会话超时请重新登录”。

SpringSecurity目前的行为:

SpringSecurity实际上是把这种请求当成未登录的请求,并抛出不允许访问的异常(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">
...

相关推荐