2010-12-09 4 views
12

Ich versuche Spring Security 3.0.5 in meiner Webanwendung zu verwenden. Grundsätzlich möchte ich einen Webservice haben, der Daten im JSON-Format über HTTP GET zurückgibt.Behandeln Sie nicht autorisierte Fehlermeldung für die Standardauthentifizierung in Spring Security

Ich habe einen RESTful-Service implementiert, der Daten zurückgibt, wenn die URL http://localhost:8080/webapp/json angefordert wird. Dies funktioniert mit dem folgenden curl Befehl

> curl http://localhost:8080/webapp/json 
{"key":"values"} 

Nachdem ich die Standardauthentifizierung mit Feder Sicherheit hinzugefügt, kann ich folgende Befehle verwenden, um die Daten, da jetzt

> curl http://localhost:8080/webapp/json 
<html><head><title>Apache Tomcat/6.0.29 - Error report ..... 
> curl -u username:password http://localhost:8080/webapp/json 
{"key":"values"} 

Die früheren Befehl gibt Standard tomcat Fehlerseite zu bekommen es erfordert Benutzername und Passwort. Meine Frage ist, ob es möglich ist, Zugriff verweigert zu behandeln, so dass es meine eigene Fehlermeldung ausgibt? heißt

> curl http://localhost:8080/webapp/json 
{"error":"401", "message":"Username and password required"} 

Hier ist meine Feder Sicherheitskonfiguration und AccessDeniedHandler. Wie Sie sehen können, versuche ich access-denied-handler hinzuzufügen, die einfach eine Zeichenkette durch die Servlet-Antwort ausgibt, aber es druckt immer noch nicht meine eigene Nachricht in der Befehlszeile.

<?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" 
     xmlns:context="http://www.springframework.org/schema/context" 
     xmlns:p="http://www.springframework.org/schema/p" 
     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
      http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd 
      http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.xsd"> 
    <global-method-security secured-annotations="enabled"/> 

    <beans:bean name="access-denied" class="webapp.error.JSONAccessDeniedHandler"></beans:bean> 

    <http auto-config="true"> 
     <access-denied-handler ref="access-denied"/> 
     <intercept-url pattern="/json" access="ROLE_USER,ROLE_ADMIN" /> 
     <http-basic /> 
    </http> 

    <authentication-manager> 
     <authentication-provider> 
      <password-encoder hash="md5"/> 
      <user-service> 
      ... 
      </user-service> 
     </authentication-provider> 
    </authentication-manager> 

</beans:beans> 

AccessDeniedHandler.java

package webapp.error; 

import java.io.IOException; 
import java.io.PrintWriter; 
import javax.servlet.ServletException; 
import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletResponse; 
import org.springframework.security.access.AccessDeniedException; 
import org.springframework.security.web.access.AccessDeniedHandler; 

public class JSONAccessDeniedHandler implements AccessDeniedHandler { 

    @Override 
    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException { 
     PrintWriter writer = response.getWriter(); 
     writer.print("{\"error\":\"401\", \"message\":\"Username and password required\"}"); 
    } 

} 
+0

erstrecken können Sie die Ausgabe von curl -S oder curl -v überprüfen? – Raghuram

+0

Ich habe meine Frage geändert. Es druckte nichts, aber es druckt nicht, was ich will. Die Curl -S und Curl -V beide Standard Tomcat 401 Fehlerseite drucken. -v hat weitere Details der Anfrage/Antwort – gigadot

Antwort

15

Ich habe mein Problem gelöst, also denke ich, ich sollte es hier teilen. Diese Konfiguration ermöglicht es dem Server, Fehlermeldungen abhängig von der anfordernden Software unterschiedlich zu senden. Wenn die Anfrage von einem Webbrowser kommt, überprüft sie den Header User-Agent und leitet sie bei Bedarf in ein Formular-Login um. Wenn die Anforderung beispielsweise von curl stammt, wird bei einer fehlgeschlagenen Authentifizierung eine Klartextfehlermeldung ausgegeben.

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

    <!-- AspectJ pointcut expression that locates our "post" method and applies security that way 
    <protect-pointcut expression="execution(* bigbank.*Service.post*(..))" access="ROLE_TELLER"/>--> 
    <sec:global-method-security secured-annotations="enabled"/> 

    <bean id="basicAuthenticationFilter" 
      class="org.springframework.security.web.authentication.www.BasicAuthenticationFilter" 
      p:authenticationManager-ref="authenticationManager" 
      p:authenticationEntryPoint-ref="basicAuthenticationEntryPoint" /> 

    <bean id="basicAuthenticationEntryPoint" 
      class="webapp.PlainTextBasicAuthenticationEntryPoint" 
      p:realmName="myWebapp"/> 

    <bean id="formAuthenticationEntryPoint" 
      class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint" 
      p:loginFormUrl="/login.jsp"/> 

    <bean id="daep" class="org.springframework.security.web.authentication.DelegatingAuthenticationEntryPoint"> 
     <constructor-arg> 
      <map> 
       <entry key="hasHeader('User-Agent','Mozilla') or hasHeader('User-Agent','Opera') or hasHeader('User-Agent','Explorer')" value-ref="formAuthenticationEntryPoint" /> 
      </map> 
     </constructor-arg> 
     <property name="defaultEntryPoint" ref="basicAuthenticationEntryPoint"/> 
    </bean> 

    <sec:http entry-point-ref="daep"> 
     <sec:intercept-url pattern="/login.jsp*" filters="none"/> 
     <sec:intercept-url pattern="/json" access="ROLE_USER,ROLE_ADMIN" /> 
     <sec:intercept-url pattern="/json/*" access="ROLE_USER,ROLE_ADMIN" /> 
     <sec:logout 
      logout-url="/logout" 
      logout-success-url="/home.jsp"/> 
     <sec:form-login 
      login-page="/login.jsp" 
      login-processing-url="/login" 
      authentication-failure-url="/login.jsp?login_error=1" default-target-url="/home.jsp"/> 
     <sec:custom-filter position="BASIC_AUTH_FILTER" ref="basicAuthenticationFilter" /> 
    </sec:http> 

    <sec:authentication-manager alias="authenticationManager"> 
     <sec:authentication-provider> 
     ... 
     </sec:authentication-provider> 
    </sec:authentication-manager> 

</beans> 

PlainTextBasicAuthenticationEntryPoint von org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint

import java.io.IOException; 
import java.io.PrintWriter; 
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.www.BasicAuthenticationEntryPoint; 

public class PlainTextBasicAuthenticationEntryPoint extends BasicAuthenticationEntryPoint { 

    @Override 
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException { 
     response.addHeader("WWW-Authenticate", "Basic realm=\"" + getRealmName() + "\""); 
     response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); 
     PrintWriter writer = response.getWriter(); 
     writer.println("HTTP Status " + HttpServletResponse.SC_UNAUTHORIZED + " - " + authException.getMessage()); 
    } 
} 
0

Ich frage mich, ob es jemals zu Ihrem AccessDeniedHandler machen wird. Ist der Fehler wegen Authentifizierung oder Autorisierung? Wird der AccessDeniedHandeler für beide Szenarien aufgerufen? Ich bin gerade dabei, das selbst zu lösen.

+0

Sie haben Recht. AccessDeniedHandler wird nicht ausgeführt, da es sich immer noch um Authentifizierungs- oder Autorisierungsprozesse handelt. – gigadot

+0

Ich habe das irgendwie gelöst. Spring Security stochert darauf und gibt es an die 401 Seiten zurück, die von Ihrer App in der web.xml definiert wurden. Nun, wenn Sie das abfangen möchten, müssen Sie Ihren eigenen AuthenticationProcessFilter schreiben und den Inhaltstyp und die Fehlerreaktion dort behandeln. Ich habe bemerkt, dass einige Leute nur den HTTP-Status Fehlermeldung dort sein lassen, aber ich mag das nicht und wird am Ende ein CustomAuthenticationProcessingFilter schreiben, der die ursprüngliche Anfrageerweiterung oder Accept Header betrachtet und die entsprechende Antwort zurückgibt. – bh5k

+0

Ich habe es etwas anders gelöst, aber es ist ziemlich mächtig, die mir erlauben, Formularanmeldung gleichzeitig zu haben. Ich habe unten gepostet. Wenn Sie Ihren Code teilen, kann dies sehr hilfreich sein – gigadot