Spring Security: HTTP Status 401 bei unautorisierten Ajax Anfragen senden

veröffentlicht am 08. Juni 2013

Ich entwickle momentan eine auf ExtJS basierende Webanwendung, die über JSON mit einem in Java implementierten Server kommuniziert. Für die Absicherung der Anwendung wird Spring Security verwendet. Nun ist es so, dass der Benutzer bei einem Seitenaufruf mit abgelaufener Session normalerweise auf die Anmeldeseite weitergeleitet wird. Bei Ajax Anfragen ist dieser Mechanismus jedoch nicht sinnvoll. Stattdessen kann Spring Security so konfiguriert werden, dass statt der Weiterleitung bei Ajax Anfragen der HTTP Status 401 (Unauthorized)  zurückgeliefert wird.

Hierzu muss zunächst ein angepasster LoginUrlAuthenticationEntryPoint implementiert werden, der sich die Eigenschaft zunutze macht, dass bei Ajax Anfragen üblicherweise der X-Requested-With Header auf den Wert XMLHttpRequest gesetzt wird. Die Implementierung ist so ausgelegt, dass die Weiterleitung bei normalen Seitenaufrufen mit abgelaufener Session weiterhin funktioniert, bei Ajax Anfragen mit abgelaufener Session jedoch der HTTP Status 401 zurückgegeben wird:

package example.security;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;

/**
 * AJAX (XMLHttpRequest) aware {@link LoginUrlAuthenticationEntryPoint}.
 * 
 * @author Patrick Gotthard
 * 
 */
public class AjaxAwareAuthenticationEntryPoint extends LoginUrlAuthenticationEntryPoint {

	public AjaxAwareAuthenticationEntryPoint(final String loginFormUrl) {
		super(loginFormUrl);
	}

	/**
	 * Sends HTTP status 401 (Unauthorized) when the <b>X-Requested-With</b> header equals <b>XMLHttpRequest</b>.
	 * Otherwise redirects to the login page.
	 */
	@Override
	public void commence(final HttpServletRequest request, final HttpServletResponse response, final AuthenticationException authException) throws IOException,
			ServletException {

		final String xRequestedWithHeader = request.getHeader("X-Requested-With");
		if ("XMLHttpRequest".equals(xRequestedWithHeader)) {
			response.sendError(401);
		} else {
			super.commence(request, response, authException);
		}

	}

}

Die Klasse muss jetzt nur noch in die Spring Security Konfiguration eingebunden werden. Beim Instanziieren muss die URL zur Anmeldeseite übergeben werden, damit die Umleitung bei normalen Seitenanfragen (ohne Ajax) weiterhin funktioniert:

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
	xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
		http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd">

	<beans:bean id="authEntryPoint" class="example.security.AjaxAwareAuthenticationEntryPoint">
		<beans:constructor-arg value="/login" />
	</beans:bean>

	<http auto-config="true" entry-point-ref="authEntryPoint">
		<!-- further security configuration [...] -->
	</http>

</beans:beans>

Hinterlasse einen Kommentar