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();

如果你真的想用自定义注解注入用户名,你需要创建一个InjectionResolverSee 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