Детализированная аутентификация с помощью RESTlet
-
19-09-2019 - |
Вопрос
Я хочу предоставить ресурс с помощью RESTlet с детализированной аутентификацией.Мой ServerResource
должен быть доступен через GET
только для прошедших проверку подлинности участников (с использованием БАЗОВОЙ аутентификации).Однако запросы, использующие POST
должен быть доступен также для абонентов без какой-либо аутентификации.
Для того, чтобы очистить:http://path/myapp/user должен разрешить любому зарегистрироваться с помощью POST
, но только зарегистрированные участники должны иметь возможность GET
список всех пользователей.
К сожалению, я не очень разбираюсь в RESTlet, и я нахожу только примеры, использующие более грубую аутентификацию для всего Restlet
ы или Router
s.
Итак, как мне включить необязательную аутентификацию для ресурсов и проверять их на уровне каждого метода?
Заранее спасибо!
Решение
Для выполнения базовой аутентификации в RESTlet 2.0 (Я предполагаю, что вы используете 2.0, поскольку вы упомянули ServerResource
), вам нужно использовать ChallengeAuthenticator
.Если это настроено с optional = true
тогда аутентификация будет запрошена только в том случае, если вы вызовете ChallengeAuthenticator.challenge()
.
Вы можете создать свое приложение с помощью authenticate()
метод и вызывайте его всякий раз, когда вам нужен защищенный доступ к ресурсу:
Применение:
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;
}
}
Ресурс:
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
// ...
}
}
Другие советы
В настоящее время я использую Restlet версии v2.0.10.
Проблема с ChallengeAuthenticator.isOptional()
заключается в том, что это все или ничего.Альтернативой ответу, предоставленному @sea36 выше, является переопределение ChallengeAuthenticator.beforeHandle()
либо выполнить аутентификацию, либо пропустить ее в зависимости от метода запроса.Например, приведенный ниже ресурс будет требовать аутентификации только при использовании метода GET.
Применение:
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;
}
}
Ресурс:
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
// ...
}
}
Обратите внимание, что в этом примере политика аутентификации при ПОЛУЧЕНИИ применяется только к UserResource
а не другие ресурсы, обрабатываемые маршрутизатором.