How to handle expired session using Spring Security and jQuery?
Here's an approach that I think is quite simple. It's a combination of approaches that I've observed on this site. I wrote a blog post about it:http://yoyar.com/blog/2012/06/dealing-with-the-spring-security-ajax-session-timeout-problem/
The basic idea is to use an api url prefix (i.e. /api/secured) as suggested above along with an authentication entry point. It's simple and works.
Here's the authentication entry point:
package com.yoyar.yaya.config;import org.springframework.security.core.AuthenticationException;import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;import javax.servlet.ServletException;import javax.servlet.http.*;import java.io.IOException;public class AjaxAwareAuthenticationEntryPoint extends LoginUrlAuthenticationEntryPoint { public AjaxAwareAuthenticationEntryPoint(String loginUrl) { super(loginUrl); } @Override public void commence( HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException { boolean isAjax = request.getRequestURI().startsWith("/api/secured"); if (isAjax) { response.sendError(403, "Forbidden"); } else { super.commence(request, response, authException); } }}
And here's what goes in your spring context xml:
<bean id="authenticationEntryPoint" class="com.yoyar.yaya.config.AjaxAwareAuthenticationEntryPoint"> <constructor-arg name="loginUrl" value="/login"/></bean><security:http auto-config="true" use-expressions="true" entry-point-ref="authenticationEntryPoint"> <security:intercept-url pattern="/api/secured/**" access="hasRole('ROLE_USER')"/> <security:intercept-url pattern="/login" access="permitAll"/> <security:intercept-url pattern="/logout" access="permitAll"/> <security:intercept-url pattern="/denied" access="hasRole('ROLE_USER')"/> <security:intercept-url pattern="/" access="permitAll"/> <security:form-login login-page="/login" authentication-failure-url="/loginfailed" default-target-url="/login/success"/> <security:access-denied-handler error-page="/denied"/> <security:logout invalidate-session="true" logout-success-url="/logout/success" logout-url="/logout"/></security:http>
I used the following solution.
In spring security defined invalid session url
<security:session-management invalid-session-url="/invalidate.do"/>
For that page added following controller
@Controllerpublic class InvalidateSession{ /** * This url gets invoked when spring security invalidates session (ie timeout). * Specific content indicates ui layer that session has been invalidated and page should be redirected to logout. */ @RequestMapping(value = "invalidate.do", method = RequestMethod.GET) @ResponseBody public String invalidateSession() { return "invalidSession"; }}
And for ajax used ajaxSetup to handle all ajax requests:
// Checks, if data indicates that session has been invalidated.// If session is invalidated, page is redirected to logout $.ajaxSetup({ complete: function(xhr, status) { if (xhr.responseText == 'invalidSession') { if ($("#colorbox").count > 0) { $("#colorbox").destroy(); } window.location = "logout"; } } });
Take a look at http://forum.springsource.org/showthread.php?t=95881, I think the proposed solution is much clearer than other answers here:
- Add a custom header in your jquery ajax calls (using 'beforeSend' hook). You can also use the "X-Requested-With" header that jQuery sends.
- Configure Spring Security to look for that header in the server side to return a HTTP 401 error code instead of taking the user to the login page.