2014-01-09 5 views
6

Я разрабатываю REST API, используя RESTEasy с Guice, и в настоящий момент я пытаюсь включить базовую аутентификацию с помощью аннотации, аналогичной @Auth, найденной в Dropwizard. СВнедрение принципала в метод ресурсов в RESTEasy с Guice

@Path("hello") 
public class HelloResource { 
    @GET 
    @Produces("application/json") 
    public String hello(@Auth final Principal principal) { 
     return principal.getUsername(); 
    } 
} 

вводное ресурс вызов должен быть перехвачен некоторый код, выполняющего основную аутентификацию, используя учетные данные, передаваемые в заголовке запроса авторизации HTTP и на успех инъекционного принципала в метод основного параметра. Я также хотел бы иметь возможность передавать список разрешенных ролей в аннотацию, например. @Auth("admin").

Мне действительно нужен совет в каком направлении идти, чтобы достичь этого?

ответ

7

Я думаю, что ваша лучшая ставка будет использовать промежуточное значение в пределах области запроса. Предполагая, что вы не поместили HelloResource в область Singleton, вы можете ввести это промежуточное значение в некоторой реализации ContainerRequestFilter и в свой ресурс, и вы можете заполнить его внутри этой версии ContainerRequestFilter со всей необходимой вам информацией авторизации и авторизации.

Это будет выглядеть примерно так:

// Authentication filter contains code which performs authentication 
// and possibly authorization based on the request 
@Provider 
public class AuthFilter implements ContainerRequestFilter { 
    private final AuthInfo authInfo; 

    @Inject 
    AuthFilter(AuthInfo authInfo) { 
     this.authInfo = authInfo; 
    } 

    @Override 
    public void filter(ContainerRequestContext requestContext) throws IOException { 
     // You can check request contents here and even abort the request completely 
     // Fill authInfo with the data you need 
     Principal principal = ...; // Ask some other service possibly 
     authInfo.setPrincipal(principal); 
    } 
} 

@Path("hello") 
public class HelloResource { 
    private final AuthInfo authInfo; 

    @Inject 
    HelloResource(AuthInfo authInfo) { 
     this.authInfo = authInfo; 
    } 

    @GET 
    @Produces("application/json") 
    public String hello() { 
     // authInfo here will be pre-filled with the principal, assuming 
     // you didn't abort the request in the filter 
     return authInfo.getPrincipal().getUsername(); 
    } 
} 

public class MainModule extends AbstractModule { 
    @Override 
    protected void configure() { 
     bind(AuthFilter.class); 
     bind(HelloResource.class); 
     bind(AuthInfo.class).in(RequestScoped.class); 
    } 
} 

И даже если вы положили ресурс (или даже фильтр) в одноплодном объеме по какой-то причине, вы всегда можете придать Provider<AuthInfo> вместо AuthInfo.

Update

Кажется, что я был несколько неправильно в том, что фильтр по умолчанию не в одноплодной области. На самом деле это похоже на синглтон, хотя он не связан как таковой. Он создается при запуске контейнера JAX-RS. Следовательно, вам нужно будет ввести Provider<AuthInfo> в фильтр. Фактически, запуск контейнера не удастся, если AuthInfo впрыснут в фильтр напрямую, будучи связанным с запросом области. Ресурс (если он явно не привязан как singleton), будет иметь место с прямой инъекцией.

Я загрузил рабочую программу в github.

+0

Спасибо! Был надеется, что есть способ вставить принципала в метод ресурса более прямо, но предположим, что я должен отказаться от этой идеи;) Когда я тестирую свой код, главный пользователь auth-информации не был установлен, когда мой метод ресурса казнены. Интересно, что я пропустил ... – Stine

+0

Угадай, что я должен создать новый вопрос о моих проблемах с предоставлением запроса на авторизацию info? – Stine

+0

@Stine, см. Мое обновление), вы были быстрее вторыми фракциями :) –

Смежные вопросы