L'authentification à grains fins avec Restlet
-
19-09-2019 - |
Question
Je veux exposer une ressource à l'aide Restlet avec une authentification à grains fins. Mon ServerResource
devrait être accessible via GET
uniquement pour les membres authentifiés (en utilisant l'authentification de base). Toutefois, les demandes en utilisant POST
devraient être disponibles également pour les appels sans authentification.
Pour clearify:
http: // chemin / myapp / utilisateur devrait permettre à quiconque d'enregistrer à l'aide POST
, mais seuls les membres inscrits devraient pouvoir GET
une liste de tous les utilisateurs.
Je ne suis malheureusement pas grand-chose en Restlet et je trouve que des exemples en utilisant l'authentification pour tout le Restlet
s grossier ou Router
s.
Alors, comment puis-je activer l'authentification facultative pour les ressources et les vérifier sur un niveau par méthode?
Merci d'avance!
La solution
Pour l'authentification de base dans Restlet 2.0 (je suppose que vous utilisez 2.0 puisque vous mentionnez ServerResource
), vous devez utiliser un ChallengeAuthenticator
. Si cela est configuré avec optional = true
alors l'authentification ne sera demandé si vous invoquez ChallengeAuthenticator.challenge()
.
Vous pouvez créer votre application avec une méthode authenticate()
et appeler cela chaque fois que vous avez besoin d'accéder à une ressource à sécuriser:
Application:
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;
}
}
Ressources:
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
// ...
}
}
Autres conseils
J'utilise actuellement v2.0.10 Restlet.
Le problème avec ChallengeAuthenticator.isOptional()
est qu'il est tout ou rien. Une alternative à la réponse fournie par @ sea36 ci-dessus est de passer outre ChallengeAuthenticator.beforeHandle()
soit effectuer l'authentification ou de l'ignorer selon la méthode de la demande. Par exemple, la ressource ci-dessous ne nécessite que l'authentification lorsque la méthode GET est utilisée.
Application:
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;
}
}
Ressources:
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
// ...
}
}
Notez que cet exemple applique la politique d'authentification GET uniquement aux UserResource
et non d'autres ressources gérées par le routeur.