Java 为什么拦截器不会在从servlet过滤器调用的EJB方法上启动?
我想用servlet过滤器在url上实现高级资源过滤,用拦截器在方法上实现低级操作过滤,但我的拦截器不会在从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"; } 拦截器:
@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");
}
}
最后,我想用EJBRulesBean
来管理我所有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;
}
}