One of the requirement in a recent project was to capture the Ajax session expiry and send a JSON response back to the client if the session was expired. There are a few different ways to handle this in Spring Security. Here is one approach
<bean id="ajaxRequestMatcher" class="com.mycompany.AjaxRequestMatcher"/> <bean id="loginEntryPoint" class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint"> <constructor-arg value="/login.jsp" /> </bean> <bean id="ajaxEntryPoint" class="com.mycompany.AjaxAuthenticationEntryPoint" /> <bean id="authenticationRequestCache" class="org.springframework.security.web.savedrequest.HttpSessionRequestCache"> <property name="requestMatcher" ref="ajaxRequestMatcher" /> </bean> <bean id="authenticationEntryPoint" class="org.springframework.security.web.authentication.DelegatingAuthenticationEntryPoint"> <constructor-arg> <map> <entry key-ref="ajaxRequestMatcher" value-ref="ajaxEntryPoint" /> </map> </constructor-arg> <property name="defaultEntryPoint" ref="loginEntryPoint" /> </bean> <security:http entry-point-ref="authenticationEntryPoint"> <security:intercept-url access="IS_AUTHENTICATED_REMEMBERED" pattern="/secure/**"/> <security:form-login login-page="/login.jsp"/> <security:logout/> </security:http>
Java Classes
public class AjaxRequestMatcher implements RequestMatcher { public boolean matches(HttpServletRequest request) { return "XMLHttpRequest".equals(request.getHeader("X-Requested-With")); } } public class AjaxAuthenticationEntryPoint extends LoginUrlAuthenticationEntryPoint { @Override public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException { // form json string String json = .... response.setContentType(MediaType.APPLICATION_JSON_VALUE); response.setHeader("Cache-control", "no-cache"); response.setStatus(HttpServletResponse.SC_FORBIDDEN); response.getWriter().print(json); response.getWriter().flush(); response.getWriter().close(); } }
An interesting reading :)
ReplyDeleteYou could use @ResponseBody and @ResponseStatus + return Map instead of writing directly to response. Additionally your solution contains a small flaw - JSON response in places where JSTL views are returned may be a bit tricky to handle in the frontend layer.
Thanks for your input.
DeleteBut I am not using Spring MVC at all. The implementation uses Spring Security with JAX-RS (RestEasy).