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).