Jersey 和 HK2 - 注入当前用户
Jersey and HK2 - Injecting current user
我正在使用 jersey 2.17 和 HK2 创建一个简单的休息应用程序。
我有一个 ContainerRequestFilter
拒绝任何没有 "currentuser" cookie 的请求。
我有这样的东西:
@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) ;
}
}
我想编写比这更优雅的代码。
像这样:
@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) ;
}
}
我是 hk2 的新手,很难找到实现它的方法。
我只是要求实现正确的接口(或 class 扩展)。
您要找的东西可不简单。处理此问题的一种方法是将 ContainerRequestFilter
内的 SecurityContext
设置为 。这不涉及与 HK2 的任何直接交互。然后您可以在资源 class 中注入 SecurityContext
。并通过
获取用户
securityContext.getUserPrincipal().getName();
如果你真的想用自定义注解注入用户名,你需要创建一个InjectionResolver
(See Defining Custom Injection Annotation。你可以注入ContainerRequestContext
(同一个在 ContainerRequestFilter
) 或 SecurityContext
中传递给过滤方法进入 InjectionResolver
。例如
过滤器
@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"));
}
}
注释
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface CurrentUser {
}
注入解析器
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; }
}
绑定注入解析器
@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;
}
}
资源
@Path("user")
public class UserResource {
@CurrentUser
private User user;
@GET
public Response getCurrentUser() {
return Response.ok(user.getUsername()).build();
}
}
现在我不太确定第二种方法,至少关于过滤器的部分是 @PreMatching
过滤器。如果我不将其设为预匹配,则 User
将为空。 ContainerRequestContext
似乎还没有我们设置的 属性,这意味着似乎正在发生的事情是 InjectResolver
在过滤器之前被调用。我需要调查一下。使其成为预匹配,IMO应该不需要。
但就我个人而言,我会选择第一种方法,只使用 SecurityContext
。完整示例在我上面提供的 link 中。通过这种方法,您可以根据需要利用 Jersey 的 RolesAllowedDynamicFeature
。
我正在使用 jersey 2.17 和 HK2 创建一个简单的休息应用程序。
我有一个 ContainerRequestFilter
拒绝任何没有 "currentuser" cookie 的请求。
我有这样的东西:
@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) ;
}
}
我想编写比这更优雅的代码。 像这样:
@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) ;
}
}
我是 hk2 的新手,很难找到实现它的方法。
我只是要求实现正确的接口(或 class 扩展)。
您要找的东西可不简单。处理此问题的一种方法是将 ContainerRequestFilter
内的 SecurityContext
设置为 SecurityContext
。并通过
securityContext.getUserPrincipal().getName();
如果你真的想用自定义注解注入用户名,你需要创建一个InjectionResolver
(See Defining Custom Injection Annotation。你可以注入ContainerRequestContext
(同一个在 ContainerRequestFilter
) 或 SecurityContext
中传递给过滤方法进入 InjectionResolver
。例如
过滤器
@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"));
}
}
注释
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface CurrentUser {
}
注入解析器
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; }
}
绑定注入解析器
@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;
}
}
资源
@Path("user")
public class UserResource {
@CurrentUser
private User user;
@GET
public Response getCurrentUser() {
return Response.ok(user.getUsername()).build();
}
}
现在我不太确定第二种方法,至少关于过滤器的部分是 @PreMatching
过滤器。如果我不将其设为预匹配,则 User
将为空。 ContainerRequestContext
似乎还没有我们设置的 属性,这意味着似乎正在发生的事情是 InjectResolver
在过滤器之前被调用。我需要调查一下。使其成为预匹配,IMO应该不需要。
但就我个人而言,我会选择第一种方法,只使用 SecurityContext
。完整示例在我上面提供的 link 中。通过这种方法,您可以根据需要利用 Jersey 的 RolesAllowedDynamicFeature
。