Детальная аутентификация с помощью RESTlet

Я хочу предоставить ресурс с помощью RESTlet с тонкой аутентификацией. Мой ServerResource должен быть доступен через GET только для аутентифицированных участников (использующих БАЗОВУЮ аутентификацию). Однако запросы с использованием POST должны быть доступны и для вызывающих абонентов без какой-либо аутентификации.

Чтобы уточнить: http://path/myapp/user должен разрешить любому регистрироваться с использованием POST, но только зарегистрированным участники должны иметь возможность GET составить список всех пользователей.

К сожалению, я не очень разбираюсь в RESTlet, и я нахожу только примеры, использующие более грубую аутентификацию для целых Restlet или Router.

Так как же включить необязательную аутентификацию для ресурсов и проверять их на уровне каждого метода?

Заранее спасибо!


person b_erb    schedule 07.02.2010    source источник


Ответы (2)


Чтобы выполнить базовую аутентификацию в 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
        // ...
    }

}
person Sam    schedule 08.02.2010
comment
Прежде всего, спасибо за ваш ответ, это выглядит многообещающе. Однако у меня есть некоторые проблемы с работой вашего кода. Например, нет метода getSubject() для ClientInfo (я использую 2.0m7). Кроме того, я не уверен, что ваш метод authenticate() верен? - person b_erb; 08.02.2010
comment
Я использовал более ранний снимок; Я обновил примеры для работы с 2.0m7. - person Sam; 09.02.2010
comment
Еще раз спасибо, теперь код компилируется и POST всегда доступен. К сожалению, GET никогда не бывает. Независимо от того, предоставляю ли я неправильные или правильные учетные данные BASIC, я всегда получаю 401. - person b_erb; 09.02.2010
comment
Я попробовал еще раз, и пример работает для меня, используя RESTlet 2.0m7. Вы запускаете пример или пытаетесь адаптировать его к своему коду? - person Sam; 09.02.2010
comment
Хорошо, извините, ваш код работает нормально! Большое спасибо за постоянную помощь! - person b_erb; 09.02.2010
comment
Спасибо за пример, очень пригодился! Только один вопрос: почему вы переопределяете аутентификатор, чтобы проверить, является ли callResponse нулевым? - person artgon; 15.09.2010
comment
Спасибо за образец кода! это очень полезно. В любом случае, у меня есть вопрос: действительно ли необходим метод аутентификации (...) вашего ExampleApp? поскольку у вас есть определенный аутентификатор, который имеет предшественника маршрутизатора в createInRoot()... поэтому я предполагаю, что он уже фильтрует все запросы еще до того, как они могут быть достигнуты маршрутизатором, следовательно, ресурс сервера... - person tinesoft; 25.04.2011

В настоящее время я использую 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
        // ...
    }
}

Обратите внимание, что в этом примере политика аутентификации GET применяется только к UserResource, а не к другим ресурсам, обрабатываемым маршрутизатором.

person jaguild    schedule 11.05.2012