2010-02-07 9 views
7

Ich möchte eine Ressource mit RESTlet mit einer feinkörnigen Authentifizierung verfügbar machen. Meine ServerResource sollte über GET nur für authentifizierte Mitglieder (mit BASIC-Authentifizierung) zugänglich sein. Anfragen mit POST sollten jedoch auch für Anrufer ohne Authentifizierung verfügbar sein.Feinkörnige Authentifizierung mit RESTlet

Um zu clearify: http://path/myapp/user sollte jemand erlauben mit POST, zu registrieren, aber nur registrierte Mitglieder auf GET eine Liste aller Benutzer in der Lage sein sollte.

Ich bin leider nicht viel in RESTlet und ich finde nur Beispiele mit gröberer Authentifizierung für ganze Restlet s oder Router s.

Wie kann ich die optionale Authentifizierung für Ressourcen aktivieren und sie auf einer pro-Methode-Ebene überprüfen?

Vielen Dank im Voraus!

Antwort

15

Um die grundlegende Authentifizierung in RESTlet 2.0 zu tun (ich nehme an, Sie verwenden 2.0, da Sie ServerResource erwähnen), müssen Sie eine ChallengeAuthenticator verwenden. Wenn dies mit optional = true konfiguriert ist, wird die Authentifizierung nur angefordert, wenn Sie ChallengeAuthenticator.challenge() aufrufen.

Sie können Ihre Anwendung mit einer authenticate() Methode erstellen, und das nennen, wenn Sie Zugriff auf eine Ressource müssen gesichert werden:

Anwendung:

package example; 

import org.restlet.*; 
import org.restlet.data.ChallengeScheme; 
import org.restlet.routing.Router; 
import org.restlet.security.*; 

public class ExampleApp extends Application { 

    private ChallengeAuthenticator authenticatior; 

    private ChallengeAuthenticator createAuthenticator() { 
     Context context = getContext(); 
     boolean optional = true; 
     ChallengeScheme challengeScheme = ChallengeScheme.HTTP_BASIC; 
     String realm = "Example site"; 

     // MapVerifier isn't very secure; see docs for alternatives 
     MapVerifier verifier = new MapVerifier(); 
     verifier.getLocalSecrets().put("user", "password".toCharArray()); 

     ChallengeAuthenticator auth = new ChallengeAuthenticator(context, optional, challengeScheme, realm, verifier) { 
      @Override 
      protected boolean authenticate(Request request, Response response) { 
       if (request.getChallengeResponse() == null) { 
        return false; 
       } else { 
        return super.authenticate(request, response); 
       } 
      } 
     }; 

     return auth; 
    } 

    @Override 
    public Restlet createInboundRoot() { 
     this.authenticatior = createAuthenticator(); 

     Router router = new Router(); 
     router.attach("/user", UserResource.class); 

     authenticatior.setNext(router); 
     return authenticatior; 
    } 

    public boolean authenticate(Request request, Response response) { 
     if (!request.getClientInfo().isAuthenticated()) { 
      authenticatior.challenge(response, false); 
      return false; 
     } 
     return true; 
    } 

} 

Ressource:

package example; 

import org.restlet.data.MediaType; 
import org.restlet.representation.EmptyRepresentation; 
import org.restlet.representation.Representation; 
import org.restlet.representation.StringRepresentation; 
import org.restlet.resource.ServerResource; 

public class UserResource extends ServerResource { 

    @Override 
    public Representation get() { 
     ExampleApp app = (ExampleApp) getApplication(); 
     if (!app.authenticate(getRequest(), getResponse())) { 
      // Not authenticated 
      return new EmptyRepresentation(); 
     } 

     // Generate list of users 
     // ... 
    }  

    @Override 
    public Representation post(Representation entity) { 
     // Handle post 
     // ... 
    } 

} 
+0

Zunächst einmal vielen Dank für Ihre Antwort, das sieht vielversprechend aus. Ich habe jedoch einige Probleme damit, dass Ihr Code funktioniert. Zum Beispiel gibt es keine 'getSubject()' Methode für ClientInfo (ich benutze 2.0m7). Außerdem bin ich nicht sicher, ob Ihre 'authenticate()' Methode korrekt ist? –

+0

Ich benutzte einen früheren Schnappschuss; Ich habe die Beispiele aktualisiert, um mit 2.0m7 zu arbeiten. – Sam

+0

Danke, jetzt, der Code kompiliert und POST ist immer verfügbar. Leider ist GET nie. Egal, ob ich keine, falsche oder korrekte BASIC Credentials erhalte, ich bekomme immer eine 401. –

5

Ich verwende derzeit Restlet v2.0.10.

Das Problem mit ChallengeAuthenticator.isOptional() ist, dass es alles oder nichts ist. Eine Alternative zu der oben von @ sea36 bereitgestellten Antwort besteht darin, ChallengeAuthenticator.beforeHandle() zu überschreiben, um entweder die Authentifizierung durchzuführen oder sie basierend auf der Anforderungsmethode zu überspringen. Zum Beispiel erfordert die Ressource unten nur die Authentifizierung, wenn die GET-Methode verwendet wird.

Anwendung:

package example; 

import org.restlet.*; 
import org.restlet.data.ChallengeScheme; 
import org.restlet.routing.Router; 
import org.restlet.security.ChallengeAuthenticator; 
import org.restlet.security.MapVerifier; 

public class ExampleApp extends Application { 

    private ChallengeAuthenticator createAuthenticator() { 
     Context context = getContext(); 
     ChallengeScheme challengeScheme = ChallengeScheme.HTTP_BASIC; 
     String realm = "Example site"; 

     // MapVerifier isn't very secure; see docs for alternatives 
     MapVerifier verifier = new MapVerifier(); 
     verifier.getLocalSecrets().put("user", "password".toCharArray()); 

     ChallengeAuthenticator authOnGet = new ChallengeAuthenticator(context, challengeScheme, realm) { 
      @Override 
      protected int beforeHandle(Request request, Response response) { 
       if (request.getMethod() == Method.GET) 
        return super.beforeHandle(request, response); 

       response.setStatus(Status.SUCCESS_OK); 
       return CONTINUE; 
      } 
     }; 

     return authOnGet; 
    } 

    @Override 
    public Restlet createInboundRoot() { 
     ChallengeAuthenticator userResourceWithAuth = createAuthenticator(); 
     userResourceWithAuth.setNext(UserResource.class); 

     Router router = new Router(); 
     router.attach("/user", userResourceWithAuth); 

     return router; 
    } 

} 

Ressource:

package example; 

import org.restlet.resource.Get; 
import org.restlet.resource.Post; 
import org.restlet.representation.Representation; 
import org.restlet.resource.ServerResource; 

public class UserResource extends ServerResource { 

    @Get 
    public Representation listUsers() { 
     // retrieve list of users and generate response 
     // ... 
    }  

    @Post 
    public void register(Representation entity) { 
     // handle post 
     // ... 
    } 
} 

Beachten Sie, dass dieses Beispiel auf GET, die Politik der Authentifizierung gilt nur für die UserResource und nicht die anderen durch den Router behandelt Ressourcen.

Verwandte Themen