ajax login with spring webMVC and spring security
At the client-side you may simulate a normal form submission to your login url via ajax. For example, in jQuery:
$.ajax({ url: "${pageContext.request.contextPath}/j_spring_security_check", type: "POST", data: $("#loginFormName").serialize(), beforeSend: function (xhr) { xhr.setRequestHeader("X-Ajax-call", "true"); }, success: function(result) { if (result == "ok") { ... } else if (result == "error") { ... } }});
At the server side, you may customize AuthenticationSuccessHandler
and AuthenticationFailureHandler
to return a value instead of redirect. Because you probably need a normal login page as well (for attempt to access a secured page via direct url), you should tell ajax calls from normal calls, for example, using header:
public class AjaxAuthenticationSuccessHandler implements AuthenticationSuccessHandler { private AuthenticationSuccessHandler defaultHandler; public AjaxAuthenticationSuccessHandler() { } public AjaxAuthenticationSuccessHandler(AuthenticationSuccessHandler defaultHandler) { this.defaultHandler = defaultHandler; } public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication auth) throws IOException, ServletException { if ("true".equals(request.getHeader("X-Ajax-call"))) { response.getWriter().print("ok"); response.getWriter().flush(); } else { defaultHandler.onAuthenticationSuccess(request, response, auth); }}}
I did something similar (thanks axtavt):
public class AjaxAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication auth) throws IOException, ServletException { if ("XMLHttpRequest".equals(request.getHeader("X-Requested-With"))) { response.getWriter().print( "{success:true, targetUrl : \'" + this.getTargetUrlParameter() + "\'}"); response.getWriter().flush(); } else { super.onAuthenticationSuccess(request, response, auth); }}}
I chose to extend the simple success handler for the default behavior on non-Ajax requests. Here's the XML to make it work:
<http auto-config="false" use-expressions="true" entry-point-ref="authenticationProcessingFilterEntryPoint"> <custom-filter position="FORM_LOGIN_FILTER" ref="authenticationFilter" />......</http><beans:bean id="authenticationProcessingFilterEntryPoint" class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint"> <beans:property name="loginFormUrl" value="/index.do" /> <beans:property name="forceHttps" value="false" /></beans:bean><beans:bean id="authenticationFilter" class= "org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter"> <beans:property name="authenticationManager" ref="authenticationManager"/> <beans:property name="filterProcessesUrl" value="/j_spring_security_check"/> <beans:property name="sessionAuthenticationStrategy" ref="sas" /> <beans:property name="authenticationFailureHandler" ref="failureHandler"/> <beans:property name="authenticationSuccessHandler" ref="successHandler"/></beans:bean><beans:bean id="successHandler" class="foo.AjaxAuthenticationSuccessHandler"> <beans:property name="defaultTargetUrl" value="/login.html"/></beans:bean><beans:bean id="failureHandler" class="foo.AjaxAuthenticationFailureHandler" />