Resteasy 3.X PreProcessInterceptor的适当替代品是什么?

33

我正在构建一个REST服务,使用本教程中描述的身份验证/授权机制:http://howtodoinjava.com/2013/06/26/jax-rs-resteasy-basic-authentication-and-authorization-tutorial/

基本上它使用PreProcessInterceptor接口来扫描目标方法的注释(来自javax.annotation.security包),这些注释描述了访问该方法所需的角色。由于这里的认证器是一个拦截器,它可以取消目标方法调用,如果需要,返回401(未经授权)。

问题在于,当前的RestEasy版本(3.0.1)中,org.jboss.resteasy.spi.interception.PreProcessInterceptor接口已经被弃用,我正在尝试使用标准的JAX-RS接口实现相同的行为,但遇到了问题。

我正在使用javax.ws.rs.ext.ReaderInterceptor接口来拦截调用。但是服务器似乎从未调用过它:该拦截器被忽略了。

我注册拦截器/资源的方式与之前的PreProcessInterceptor相同,并使用相同的@Provider和@ServerInterceptor注释:

ServerApplication:

public class ServerApplication extends javax.ws.rs.core.Application {

     private final HashSet<Object> singletons = new LinkedHashSet<Object>();

     public ServerApplication() {
         singletons.add(new SecurityInterceptor());
         singletons.add( ... ); //add each of my rest resources
     }

    @Override
    public Set<Class<?>> getClasses() {
        HashSet<Class<?>> set = new HashSet<Class<?>>();
        return set;
    }

    @Override
    public Set<Object> getSingletons() {
        return singletons;
    }
}

安全拦截器:

@Provider
@ServerInterceptor
public class SecurityInterceptor implements javax.ws.rs.ext.ReaderInterceptor {
     @Override
     public Object aroundReadFrom(ReaderInterceptorContext context){
            //code that is never called... so lonely here...
     }
}

有什么见解可以帮我解决这个问题吗?

谢谢。

3个回答

29

RESTEasy 3.x.x 符合 JAX-RS 2.0 规范。

您尝试的操作可以通过以下方式实现(或许更好):

@Provider
public class SecurityInterceptor 
      implements javax.ws.rs.container.ContainerRequestFilter {
     @Override
     public void filter(ContainerRequestContext requestContext){
       if (not_authenticated){ requestContext.abortWith(response)};
     }
}

由于标准 JAX-RS 流程仅在底层的 MessageBodyReader.readFrom 方法被调用时才会调用 ReaderInterceptor,而不是来自应用程序代码。

然而,你的拦截器未被调用的原因可能是 @ServerInterceptor 注释,这是一个 RESTEasy 扩展。

规范在 §6.5.2 中说明拦截器是全局注册的,除非 @Provider 注释使用了 @NameBinding 注释。但我不知道 RESTEasy 是否可以处理未显式注册的 @ServerInterceptor,如 RestEASY Interceptor Not Being Called所示。


使用ContainerRequestFilter,我如何获取目标方法的注释?过滤器/拦截器需要知道这一点,以便根据用户角色正确允许或拒绝调用。 - Gilberto Torrezan
ContainerRequestFilter.getUriInfo().getMatchedResources() 返回匹配的资源对象列表。在那里,您可以解析与实际调用方法匹配的注释。 - Carlo Pellegrini
1
我认为你的意思是 requestContext.getUriInfo().getMatchedResources()。无论如何,与以前的 PreProcessInterceptor 不同,这种方法不太容易使用,因为我没有直接访问目标 java.lang.reflect.Method。但既然它解决了问题,我会将答案标记为已接受。 - Gilberto Torrezan
这就是我的意思。很抱歉打错了字。你考虑过使用requestContext.setSecurityContext()来注入你的身份验证,然后委托给@RolesAllowed注解吗? - Carlo Pellegrini
使用@Context注释来注入ResourceInfo将使您可以访问目标Method。请参见相关链接:https://dev59.com/W14b5IYBdhLWcg3wZwy3#29201811 - MathieuB

4
如果您需要访问底层的java.lang.reflect.Method(就像您以前通过实现AcceptedByMethod接口所能够获取的那样),您可以按照以下方式进行操作:
ResourceMethodInvoker methodInvoker = (ResourceMethodInvoker) 
            requestContext.getProperty("org.jboss.resteasy.core.ResourceMethodInvoker");
Method method = methodInvoker.getMethod();

1
如何从requestContext获取httpRequest?我需要从httpRequest读取InputStream。怎么做呢?或者有没有一种方法可以从containerrequestcontext获取InputStream? - arun_kk
我从methodInvoker中得到了空引用,不知道为什么。 - Vinh.TV

3
我还想访问底层的java.lang.reflect.Method,并尝试了mtpettyp的答案与Resteasy 3.0.8一起使用,但在getProperty调用上返回null。我也在使用Spring和resteasy-spring,尽管我不认为这会对此产生影响。
如果你遇到我的情况,并且正在实现一个Post匹配ContainerRequestFilter(如果你希望获取匹配的资源方法,你必须这样做),那么你实际上可以将ContainerRequestContext转换为Resteasy在Post Match场景下的实现。 PostMatchContainerRequestContext引用了ResourceMethodInvoker。
public void filter(ContainerRequestContext context) throws IOException {
    PostMatchContainerRequestContext pmContext = (PostMatchContainerRequestContext) context;

    Method method = pmContext.getResourceMethod().getMethod();

    /* rest of code here */
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接