java dependency-injection jersey jersey-2.0 hk2

java - Jersey y HK2-usuario actual de inyección



dependency-injection jersey-2.0 (1)

Estoy trabajando con jersey 2.17 y HK2 para crear una aplicación de descanso simple. Tengo un ContainerRequestFilter que rechaza cualquier solicitud que no tenga la cookie "usuario actual".

Tengo algo como esto:

@Path("/users") public class UserResource { private UserService userService; @GET @Path("/orders") @Produces("application/json") public List<Order> findOrdersOfCurrentUser() { // some ugly code to access headers, extract cookies, and finally // extract username (a String) from a particular cookie return this.userService.findOrdersByUsername(username) ; } }

Quiero codificar algo más elegante que eso. Me gusta esto:

@Path("/users") public class UserResource { private UserService userService; @CurrentUsername private String currentUser; @GET @Path("/orders") @Produces("application/json") public List<Order> findOrdersOfCurrentUser() { return this.userService.findOrdersByUsername(username) ; } }

Soy muy nuevo en hk2 y me resulta muy difícil encontrar la manera de hacerlo.

Solo estoy pidiendo la interfaz correcta para implementar (o clase para ampliar).


Lo que estás buscando no se hace trivialmente. Una forma de manejar esto es establecer el SecurityContext dentro de ContainerRequestFilter , como se ve aquí . Esto no implica ninguna interacción directa con HK2. A continuación, puede inyectar SecurityContext en su clase de recursos. Y obtener el usuario por

securityContext.getUserPrincipal().getName();

Si realmente desea agregar el nombre de usuario con una anotación personalizada, deberá crear un InjectionResolver ( consulte Definición de la anotación de inyección personalizada . Puede inyectar ContainerRequestContext (el mismo que pasó al método de filtro en el ContainerRequestFilter ) o el SecurityContext en el InjectionResolver . Por ejemplo

Filtrar

@Provider @PreMatching public class UserFilter implements ContainerRequestFilter { public static final String USER_PROP = "user"; @Override public void filter(ContainerRequestContext requestContext) throws IOException { requestContext.setProperty(USER_PROP, new User("peeskillet")); } }

Anotación

@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface CurrentUser { }

InjectionResolver

public class CurrentUserInjectionResolver implements InjectionResolver<CurrentUser> { javax.inject.Provider<ContainerRequestContext> requestContext; @Inject public CurrentUserInjectionResolver( javax.inject.Provider<ContainerRequestContext> requestContext) { this.requestContext = requestContext; } @Override public Object resolve(Injectee injectee, ServiceHandle<?> sh) { if (User.class == injectee.getRequiredType()) { return requestContext.get().getProperty(UserFilter.USER_PROP); } return null; } @Override public boolean isConstructorParameterIndicator() { return false; } @Override public boolean isMethodParameterIndicator() { return false; } }

Enlace el InjectionResolver

@Provider public class UserFeature implements Feature { @Override public boolean configure(FeatureContext context) { context.register(new AbstractBinder(){ @Override public void configure() { bind(CurrentUserInjectionResolver.class) .to(new TypeLiteral<InjectionResolver<CurrentUser>>(){}) .in(Singleton.class); } }); return true; } }

Recurso

@Path("user") public class UserResource { @CurrentUser private User user; @GET public Response getCurrentUser() { return Response.ok(user.getUsername()).build(); } }

Ahora no estoy seguro de este segundo enfoque, al menos la parte sobre el filtro es un filtro @PreMatching . Si no hago una pre-coincidencia, el User será nulo. Parece que ContainerRequestContext aún no tiene la propiedad que establecimos, lo que significa que lo que parece estar sucediendo es que se llama a InjectResolver antes del filtro. Tendré que investigar esto. Haciéndolo una pre-coincidencia, IMO no debería ser requerido.

Personalmente, me gustaría ir con el primer enfoque, simplemente usando el SecurityContext . Un ejemplo completo está en el enlace que proporcioné arriba. Con este enfoque, puede aprovechar la RolesAllowedDynamicFeature de Jersey si es necesario.