Java 为什么拦截器不会在从servlet过滤器调用的EJB方法上启动?

Java 为什么拦截器不会在从servlet过滤器调用的EJB方法上启动?,java,servlets,ejb,servlet-filters,interceptor,Java,Servlets,Ejb,Servlet Filters,Interceptor,我想用servlet过滤器在url上实现高级资源过滤,用拦截器在方法上实现低级操作过滤,但我的拦截器不会在从servlet过滤器调用的EJB方法上启动 拦截器注释接口: @Inherited @InterceptorBinding @Retention (RUNTIME) @Target({TYPE, METHOD}) public @interface Permit { @Nonbinding String[] actions() default "N/A"; } 拦截器:

我想用servlet过滤器在url上实现高级资源过滤,用拦截器在方法上实现低级操作过滤,但我的拦截器不会在从servlet过滤器调用的EJB方法上启动

拦截器注释接口:

@Inherited
@InterceptorBinding
@Retention (RUNTIME)
@Target({TYPE, METHOD})
public @interface Permit {
    @Nonbinding
    String[] actions() default "N/A";
}
拦截器:

@Permit
@Interceptor
public class PermitInterceptor {

    @AroundInvoke
    public Object verifyPermission(InvocationContext context) throws Exception {
        Method method = context.getMethod();
        if(method.isAnnotationPresent(Permit.class)) {
            Permit permitAnnotation = method.getAnnotation(Permit.class);
            List<String> permittedActions = Arrays.asList(permitAnnotation.actions());
            List<String> userActions = SecurityContextHandler.getActiveUser().getActions();
            if(!Collections.disjoint(permittedActions, userActions)){
                return context.proceed();
            }
        }
        throw new PermissionException("You do NOT have the required permissions to perform this action");
    }
}
最后,我想用EJB
RulesBean
来管理我所有servlet的路由/拦截

规则:

@Stateless
@LocalBean
public class RulesBean {
    private static final String CUSTOMERS = "/customers"

    public boolean isAllowed(String url) throws PermissionException {
        switch(url){
            case CUSTOMERS: return canViewAllCustomers();
            default: return true;
        }
    }

    /*This should trigger PermitInterceptor before entering method and 
    should throw my custom PermissionException if permission fails*/
    @Permit(actions={"ViewCustomers"}) 
    private boolean canViewAllCustomers(){
        return true;
    }
    ...
    //Other tests carried out here ...
}
不幸的是,在输入
canViewAllCustomers()
方法之前,不会调用
permittinterceptor

然而,令人惊讶的是,当
canViewAllCustomers()
被公开并直接作为
规则调用时,
PermitInterceptor
被触发。canViewAllCustomers()
而不是通过帮助器方法
规则。isAllowed(字符串url)
。但这对我的情况没有帮助,因为它没有为我的URL检查提供单个入口点,这基本上意味着我必须在Servlet过滤器中执行所有检查

问题:有人能解释一下为什么事情会以这种方式发生吗?。。。关于实现此方案的最佳方法的建议非常受欢迎。谢谢
注意:(提供更多视角) 您可能想知道我为什么要这样做,或者更具体地说,为什么
RuleBean
甚至存在。。。原因很简单,因为我的许多servlet除了将响应路由到一个触发服务器端DataTables ajax调用的视图(该调用填充了表)之外,没有做什么,因此,我确实需要确保对视图的请求甚至不会到达获取视图的
if…else
条件,除非满足拦截器中的权限检查

参见下面的示例servlet

@WebServlet ("/customers/*")
public class CustomerServlet extends VelocityViewServlet {
    private static final String CUSTOMERS = "/customers"

    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String uri = request.getRequestURI();
        if(uri.equals(CUSTOMERS)){
            String view = Path.getTemplate("/customers/index.vm");
            request.setAttribute("headerTitle", "Customers");
            request.getRequestDispatcher(view).forward(request, response);
        }else if(...){
            ...
        }
    }
}

直接调用
isAllowed()
中的
canViewAllCustomers()
,这样应用程序服务器就没有机会拦截调用

拦截与代理类一起工作。当您将EJB注入servlet时,就像您在以下方面所做的那样:

@EJB
private RulesBean rules;
实际注入的不是EJB实例,而是应用服务器在运行时创建的代理类(您可以通过调试器看到这一点)。该代理类上的调用将被拦截用于事务、自定义拦截器等,然后委托给实际的类实例

因此,您需要做的是将
canViewAllCustomers()
放入一个新的EJB,您可以让应用程序服务器注入到
RulesBean
类中, 或者您可以从
isAllowed()
内部检索
RulesBean
类的引用,如下所示:

@Stateless
@LocalBean
public class RulesBean {
    private static final String CUSTOMERS = "/customers"

    @Resource
    SessionContext ctx;

    public boolean isAllowed(String url) throws PermissionException {
        switch(url){
            case CUSTOMERS: return self().canViewAllCustomers(); 
            default: return true;
        }
    }

    private RulesBean self() {
        return ctx.getBusinessObject(RulesBean.class);
    }

    /*This should trigger PermitInterceptor before entering method and 
    should throw my custom PermissionException if permission fails*/
    @Permit(actions={"ViewCustomers"}) 
    public boolean canViewAllCustomers(){
        return true;
    }
}

哦,谢谢!这正是事实,注入
@Resource SessionContext
解决了问题。
@Stateless
@LocalBean
public class RulesBean {
    private static final String CUSTOMERS = "/customers"

    @Resource
    SessionContext ctx;

    public boolean isAllowed(String url) throws PermissionException {
        switch(url){
            case CUSTOMERS: return self().canViewAllCustomers(); 
            default: return true;
        }
    }

    private RulesBean self() {
        return ctx.getBusinessObject(RulesBean.class);
    }

    /*This should trigger PermitInterceptor before entering method and 
    should throw my custom PermissionException if permission fails*/
    @Permit(actions={"ViewCustomers"}) 
    public boolean canViewAllCustomers(){
        return true;
    }
}