2010-02-07 18 views
7

Quiero exponer un recurso usando RESTlet con una autenticación de grano fino. Mi ServerResource debe ser accesible a través de GET solo para miembros autenticados (usando autenticación BASIC). Sin embargo, las solicitudes que usan POST también deberían estar disponibles para las personas que llaman sin ninguna autenticación.Autenticación de grano fino con RESTlet

Para clearify: http://path/myapp/user debería permitir que cualquier persona se registra utilizando POST, pero sólo los usuarios registrados deben ser capaces de GET una lista de todos los usuarios.

Desafortunadamente, no me gustan mucho los RESTlet y solo encuentro ejemplos que usan autenticación más gruesa para Restlet s completos o Router s.

Entonces, ¿cómo habilito la autenticación opcional para los recursos y los compruebo en un nivel por método?

¡Gracias de antemano!

Respuesta

15

Para realizar la autenticación básica en RESTlet 2.0 (supongo que está utilizando 2.0 ya que menciona ServerResource), debe utilizar un ChallengeAuthenticator. Si esto está configurado con optional = true, entonces la autenticación solo se solicitará si invoca ChallengeAuthenticator.challenge().

Puede crear su aplicación con un método authenticate(), y llamar a esto cada vez que necesite acceso a un recurso para ser asegurado:

Aplicación:

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; 
    } 

} 

de recursos:

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

En primer lugar, gracias por su respuesta, esto parece prometedor. Sin embargo, tengo algunos problemas para hacer que tu código funcione. Por ejemplo, no hay un método 'getSubject()' para ClientInfo (estoy usando 2.0m7). Además, no estoy seguro de si su método 'authenticate()' es correcto? –

+0

Estaba usando una instantánea anterior; He actualizado los ejemplos para trabajar con 2.0m7. – Sam

+0

Gracias, una vez más, ahora el código se compila y POST siempre está disponible. Desafortunadamente, GET nunca es. No importa si proporciono credenciales BÁSICAS incorrectas o incorrectas, siempre obtengo un 401. –

5

Actualmente estoy usando Restlet v2.0.10. El problema con ChallengeAuthenticator.isOptional() es que es todo o nada. Una alternativa a la respuesta proporcionada por @ sea36 anterior es anular ChallengeAuthenticator.beforeHandle() para realizar la autenticación u omitirla según el método de solicitud. Por ejemplo, el recurso a continuación solo requerirá autenticación cuando se use el método GET.

Aplicación:

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; 
    } 

} 

de recursos:

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 
     // ... 
    } 
} 

Tenga en cuenta que este ejemplo se aplica la política de autenticación de obtener sólo a los demás y no UserResource recursos manejados por el router.

Cuestiones relacionadas