Jersey - 从过滤器中注入变量作为 RequestScoped
Jersey - Inject variable from filter as RequestScoped
我想在调用我的资源方法之前在过滤器中执行身份验证。在这个过滤器中,我还想检索用户的权限并通过 RequestScoped @Inject 注释传递它。
@Authenticated
public class AuthenticationFilter implements ContainerRequestFilter {
@NameBinding
@Retention(RetentionPolicy.RUNTIME)
public @interface Authenticated {};
@Inject
private ISecurityHandler handler;
public AuthenticationFilter() {}
@Override
public void filter(ContainerRequestContext requestContext) throws IOException {
// Filter out unauthorized
// Retrieve user permissions
this.handler.setUserPermissions(...);
}
}
资源:
@Path("my-path")
public class GetVisitorsDataResource {
@Inject private ISecurityHandler handler;
@GET
@Path("resource-method")
@Authenticated
@Produces(MediaType.APPLICATION_JSON)
public Response resource() {
System.out.println(handler.getUserPermissions());
return Response.ok().build();
}
}
我已经为注入注册了过滤器和工厂。
public static class SecurityHandlerProvider implements Factory<ISecurityHandler> {
@Override
public ISecurityHandler provide() {
System.out.println("PROVIDING SECURITY CONTEXT!");
return new SecurityHandlerImpl();
}
@Override
public void dispose(ISecurityHandler instance) {
System.out.println("DISPOSING SECURITY CONTEXT!");
}
}
我也绑定了
bindFactory(SecurityHandlerProvider.class).to(ISecurityHandler.class).in(RequestScoped.class);
重要的是对象在收到请求时创建并且只能在该请求中访问。请求完成后,应调用 dispose 方法。我可以实现类似功能的唯一方法是通过 @Singleton 注释。但是,该对象不会在请求完成后被销毁,并且会在所有请求之间共享。
我已经在这个问题上投入了太多时间,是否有人知道如何获得理想的结果?
你的代码没有多大意义。一个地方你注入ISecurityHandler
,另一个地方SecurityHandler
,但是工厂是为ISecurityContext
注入的。我将假设这些是拼写错误或复制粘贴错误。
除此之外,我会假设真的一切正常,因为你说过它作为一个单例工作。所以我猜你正面临 "Not inside a request scope" 错误。最简单的解决方法是使用 javax.inject.Provider
注入,这允许我们延迟检索对象。检索对象时,它将在请求范围内。
@Inject
private javax.inject.Provider<ISecurityContext> securityContextProvider;
@Override
public void filter(ContainerRequestContext context) throws IOException {
ISecurityContext sc = securityContextProvider.get();
}
...
bindFactory(SecurityHandlerProvider.class)
.to(ISecurityContext.class)
.in(RequestScoped.class);
注意,你还应该确保用 @Priority(Priorities.AUTHENTICATION)
注释你 AuthenticationFilter
以便它出现在任何其他过滤器之前,即使你更喜欢它是 @PreMatching
过滤器。身份验证越早进入系统越好,我想说。
顺便说一句,您可能想看看泽西岛的 RolesAllowedDynamicFeature
。它允许您将 jsr250 注释 @RolesAllowed
、@DenyAll
和 @PermitAll
用于您的资源 类 和方法。
它基本上是在您的 Priorites.AUTHENTICATION
过滤器之后发生的过滤器,它从 ContainerRequestContext
中查找 javax.ws.rs.core.SecurityContext
以查找角色。您只需要在身份验证过滤器中创建 SecurityContext
,以便下一个过滤器可以查找它。
你可以看一个例子。您可以在 isUserInRole
中检查用户权限。当设置 SecurityContext
时,Jersey 的过滤器将在之后调用,它会调用您的 isUserInRole
。这样做,您就可以免费获得访问控制。
我想在调用我的资源方法之前在过滤器中执行身份验证。在这个过滤器中,我还想检索用户的权限并通过 RequestScoped @Inject 注释传递它。
@Authenticated
public class AuthenticationFilter implements ContainerRequestFilter {
@NameBinding
@Retention(RetentionPolicy.RUNTIME)
public @interface Authenticated {};
@Inject
private ISecurityHandler handler;
public AuthenticationFilter() {}
@Override
public void filter(ContainerRequestContext requestContext) throws IOException {
// Filter out unauthorized
// Retrieve user permissions
this.handler.setUserPermissions(...);
}
}
资源:
@Path("my-path")
public class GetVisitorsDataResource {
@Inject private ISecurityHandler handler;
@GET
@Path("resource-method")
@Authenticated
@Produces(MediaType.APPLICATION_JSON)
public Response resource() {
System.out.println(handler.getUserPermissions());
return Response.ok().build();
}
}
我已经为注入注册了过滤器和工厂。
public static class SecurityHandlerProvider implements Factory<ISecurityHandler> {
@Override
public ISecurityHandler provide() {
System.out.println("PROVIDING SECURITY CONTEXT!");
return new SecurityHandlerImpl();
}
@Override
public void dispose(ISecurityHandler instance) {
System.out.println("DISPOSING SECURITY CONTEXT!");
}
}
我也绑定了
bindFactory(SecurityHandlerProvider.class).to(ISecurityHandler.class).in(RequestScoped.class);
重要的是对象在收到请求时创建并且只能在该请求中访问。请求完成后,应调用 dispose 方法。我可以实现类似功能的唯一方法是通过 @Singleton 注释。但是,该对象不会在请求完成后被销毁,并且会在所有请求之间共享。
我已经在这个问题上投入了太多时间,是否有人知道如何获得理想的结果?
你的代码没有多大意义。一个地方你注入ISecurityHandler
,另一个地方SecurityHandler
,但是工厂是为ISecurityContext
注入的。我将假设这些是拼写错误或复制粘贴错误。
除此之外,我会假设真的一切正常,因为你说过它作为一个单例工作。所以我猜你正面临 "Not inside a request scope" 错误。最简单的解决方法是使用 javax.inject.Provider
注入,这允许我们延迟检索对象。检索对象时,它将在请求范围内。
@Inject
private javax.inject.Provider<ISecurityContext> securityContextProvider;
@Override
public void filter(ContainerRequestContext context) throws IOException {
ISecurityContext sc = securityContextProvider.get();
}
...
bindFactory(SecurityHandlerProvider.class)
.to(ISecurityContext.class)
.in(RequestScoped.class);
注意,你还应该确保用 @Priority(Priorities.AUTHENTICATION)
注释你 AuthenticationFilter
以便它出现在任何其他过滤器之前,即使你更喜欢它是 @PreMatching
过滤器。身份验证越早进入系统越好,我想说。
顺便说一句,您可能想看看泽西岛的 RolesAllowedDynamicFeature
。它允许您将 jsr250 注释 @RolesAllowed
、@DenyAll
和 @PermitAll
用于您的资源 类 和方法。
它基本上是在您的 Priorites.AUTHENTICATION
过滤器之后发生的过滤器,它从 ContainerRequestContext
中查找 javax.ws.rs.core.SecurityContext
以查找角色。您只需要在身份验证过滤器中创建 SecurityContext
,以便下一个过滤器可以查找它。
你可以看一个例子isUserInRole
中检查用户权限。当设置 SecurityContext
时,Jersey 的过滤器将在之后调用,它会调用您的 isUserInRole
。这样做,您就可以免费获得访问控制。