I am trying to integrate Spring Security (4.0.1) with AngularJS. I am able to do basic authentication using XML based configuration. The problem is, Web browser displays Pop up every time user enters invalid credentials. I have tried to remove WWW-Authenticate repsone header using plain ServletFilters as well as using Spring security based Custom filters. No success yet. Can anybody help me on this?
Extend default ExceptionTranslationFilter
that returns an HTTP 401 for all ajax requests instead of a basic authentication challenge:
package mypackage;
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.ExceptionTranslationFilter;
public class AjaxExceptionTranslationFilter extends ExceptionTranslationFilter {
@Autowired
public AjaxExceptionTranslationFilter(AuthenticationEntryPoint authenticationEntryPoint) {
super(authenticationEntryPoint);
}
@Override
protected void sendStartAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, AuthenticationException reason)
throws ServletException, IOException {
boolean isAjax = "XMLHttpRequest".equals(request.getHeader("X-Requested-With"));
if (isAjax) {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
} else {
super.sendStartAuthentication(request, response, chain, reason);
}
}
}
Add AjaxExceptionTranslationFilter
to your configuration right before default FILTER_SECURITY_INTERCEPTOR
:
<security:http pattern="/**">
<security:custom-filter before="FILTER_SECURITY_INTERCEPTOR" ref="exceptionTranslationFilter"/>
<!-- ... -->
</security:http>
<bean id="exceptionTranslationFilter" class="mypackage.AjaxExceptionTranslationFilter">
<constructor-arg ref="loginUrlAuthenticationEntryPoint"/>
</bean>
You'll need to add an interceptor for HTTP header X-Requested-With
to your ajax calls in your angular app in order to trigger AjaxExceptionTranslationFilter
in the backend.
Further you should catch an HTTP 401 response from the backend and handle it accordingly.
$httpProvider.interceptors.push(['$q', function($q) {
return {
'responseError': function(rejection) {
if(rejection.status === 401) {
// .. do something meaningful
}
return $q.reject(rejection);
}
};
}]);
$httpProvider.interceptors.push(['$q', function ($q) {
return {
'request': function (config) {
config.headers["X-Requested-With"] = "XMLHttpRequest";
return config || $q.when(config);
}
};
}]);
}]);