2010-02-07 2 views
7

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

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

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

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

Заранее благодарен!

ответ

15

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

} 
+0

Прежде всего спасибо за ваш ответ, это выглядит многообещающим. Тем не менее, у меня есть некоторые проблемы с тем, чтобы ваш код работал. Например, для ClientInfo нет метода 'getSubject()' (я использую 2.0m7). Кроме того, я не уверен, правильный ли метод 'authenticate()'? –

+0

Я использовал более ранний снимок; Я обновил примеры для работы с 2.0m7. – Sam

+0

Спасибо, опять же, теперь компилируется код и POST. К сожалению, GET никогда не бывает. Независимо от того, предоставляю ли я никаких, неправильных или правильных учетных данных BASIC, я всегда получаю 401. –

5

В настоящее время я использую 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, а не другим ресурсам, обрабатываемых маршрутизатор.