如何从球衣过滤器中排除一些网址?

Posted

技术标签:

【中文标题】如何从球衣过滤器中排除一些网址?【英文标题】:How to exclude some url from jersey filter? 【发布时间】:2017-01-12 17:27:18 【问题描述】:

我使用 jersey 创建 web 服务。我使用ContainerRequestFilter 创建了请求过滤器。我已经处理了Jersey Request Filter only on certain URI 问题,但我只想排除某些网址的过滤器。

@Provider
public class AuthFilter implements ContainerRequestFilter

    @Override
    public void filter(ContainerRequestContext requestContext) throws IOException 

// business logic

   

【问题讨论】:

***.com/questions/3125296/… 我说的是 jersey 过滤器而不是 servlet 过滤器。 Cássio Mazzochi Molin 的响应将起作用,但是,使用 filterchain.doFilter() 作为返回;中止请求 【参考方案1】:

您可能可以使用getUri检查 URL 模式并中止请求

类似下面的内容

public class AuthFilter implements ContainerRequestFilter

    @Override
    public void filter(ContainerRequestContext requestContext) throws IOException 

       String path =    requestContext.getUriInfo().getPath();
       if(path.contains("admin"))
          requestContext.abortWith(new Response());
       

   

https://eclipse-ee4j.github.io/jersey.github.io/documentation/latest/filters-and-interceptors.html#d0e9339

【讨论】:

请注意,return 指令不会中止请求,正如您在回答中提到的那样。它将中止过滤器的执行。要中止请求,可以抛出异常或调用ContainerRequestContext#abortWith(Response) 方法。 ContainerRequestContext#getUri() 方法不存在。应该是ContainerRequestContext#getUriInfo() 与在过滤器中对 url 进行“硬”编码相比,名称绑定是更好的解决方案。每次需要添加新的 url 时都需要更新此类/方法。【参考方案2】:

名称绑定过滤器

您可以考虑使用名称绑定过滤器来选择您的过滤器将绑定到的端点,而不是从全局过滤器中排除URI。

还可以查看 this answer 以获取一些使用名称绑定过滤器的示例。

全局过滤器

如果您仍然对全局过滤方法感到满意,您可以考虑使用UriInfo 接口来获取有关请求的 URI 的详细信息。使用以下方法之一获取UriInfo 的实例:

    使用@Context注解:

    @Provider
    public class AuthFilter implements ContainerRequestFilter 
    
        @Context
        private UriInfo info;
    
        @Override
        public void filter(ContainerRequestContext requestContext) throws IOException 
            ...
        
    
    

    ContainerRequestContext获取它:

    @Override
    public void filter(ContainerRequestContext requestContext) throws IOException 
        UriInfo info = requestContext.getUriInfo();
        ...
    
    

一旦您拥有UriInfo 实例,您就可以访问一系列可能有用的方法:

getAbsolutePath():获取请求的绝对路径。 getBaseUri():获取应用的基本 URI。 getMatchedResources():获取当前匹配的资源类实例的只读列表。 getMatchedURIs():获取匹配资源的只读 URI 列表。 getPath():以字符串形式获取当前请求相对于基本 URI 的路径。 getPathSegments():以PathSegment 列表的形式获取当前请求相对于基本 URI 的路径。 getRequestUri():获取包含任何查询参数的绝对请求 URI。 relativize(URI):相对于当前请求 URI 将 URI 相对化。 resolve(URI):根据应用程序的基本 URI 解析一个相对 URI。

有关详细信息,请查看UriInfo 文档。

如果请求的 URI 与您要应用过滤器的 URI 不匹配,只需使用 return 指令:

@Override
public void filter(ContainerRequestContext requestContext) throws IOException 
    UriInfo info = requestContext.getUriInfo();
    if (!info.getPath().contains("secured")) 
        return;
    

动态绑定

另一种方法是动态绑定。它允许您以动态方式将过滤器和拦截器分配给资源方法。上面提到的名称绑定使用静态方法,对绑定的更改需要更改源代码和重新编译。使用动态绑定,您可以实现在应用程序初始化期间定义绑定的代码。

从Jersey documentation 中提取的以下示例显示了如何实现动态绑定:

@Path("helloworld")
public class HelloWorldResource 

    @GET
    @Produces("text/plain")
    public String getHello() 
        return "Hello World!";
    

    @GET
    @Path("too-much-data")
    public String getVeryLongString() 
        String str = ... // very long string
        return str;
    

// This dynamic binding provider registers GZIPWriterInterceptor
// only for HelloWorldResource and methods that contain
// "VeryLongString" in their name. It will be executed during
// application initialization phase.
public class CompressionDynamicBinding implements DynamicFeature 

    @Override
    public void configure(ResourceInfo resourceInfo, FeatureContext context) 
        if (HelloWorldResource.class.equals(resourceInfo.getResourceClass())
                && resourceInfo.getResourceMethod().getName().contains("VeryLongString")) 
            context.register(GZIPWriterInterceptor.class);
        
    

绑定是使用实现DynamicFeature 接口的提供者完成的。该接口定义了一个带有两个参数的configure 方法,ResourceInfoFeatureContext

ResourceInfo 包含有关可以完成绑定的资源和方法的信息。将为应用程序中定义的每个资源方法执行一次配置方法。在上面的示例中,提供程序将被执行两次,一次用于getHello() 方法,一次用于getVeryLongString()(一次resourceInfo 将包含有关getHello() 方法的信息,一次它将指向getVeryLongString())。

如果动态绑定提供者想要为实际资源方法注册任何提供者,它将使用提供的 FeatureContext 来实现,该 FeatureContext 扩展了 JAX-RS 可配置 API。可以使用用于注册过滤器或拦截器类或实例的所有方法。这种动态注册的过滤器或拦截器将只绑定到实际的资源方法。在上面的示例中,GZIPWriterInterceptor 将仅绑定到方法 getVeryLongString(),这将导致仅针对此方法而不是针对方法 getHello() 压缩数据。

请注意,使用动态绑定注册的过滤器和拦截器只是为资源方法运行的附加过滤器。如果有任何名称绑定提供者或全局提供者,它们仍将被执行。


更多详情,请查看Jersey documentation about filters and interceptors。

【讨论】:

这适用于哪个球衣版本? @RicardoVigatti Jersey 2.x.【参考方案3】:

使用@NameBinding 可能是最优雅的方法,但如果您只想排除单个资源并将过滤器应用于所有其他资源,则必须记住将绑定注释放在所有资源上。在这种情况下,您可以使用ContainerRequestContext.getUriInfo().getMatchedResources() 来检查目标资源是否已匹配。这比硬编码可能会改变的路径要好。

下面的示例将对除 StatusResource 之外的所有资源应用过滤逻辑:

public class CorsContainerRequestFilter implements ContainerRequestFilter 

    @Override
    public void filter(ContainerRequestContext req) 
        if (!matchesStatusResource(req)) 
            // filter logic
        
    

    private boolean matchesStatusResource(ContainerRequestContext req) 
        List<Object> matchedResources = req.getUriInfo().getMatchedResources();
        for (Object matchedResource : matchedResources) 
            if (matchedResource instanceof StatusResource) 
                return true;
            
        
        return false;
    

正如其他人所提到的,可以使用动态绑定,但它非常难看,因为过滤器不会应用于所有资源并不明显。

【讨论】:

应该注意.getMatchedResources 不适用于具有@PreMatching 注释的过滤器,因为filter 方法将在任何资源匹配之前运行制作。

以上是关于如何从球衣过滤器中排除一些网址?的主要内容,如果未能解决你的问题,请参考以下文章

如何在球衣资源方法中覆盖@JsonView

如何在 drf-yasg 中排除特定端点的显示过滤器

如果另一个类的复选框已被选中,如何从 jQuery 过滤器中排除某个复选框类?

如何排除按钮被过滤?

bigQuery 和 GA-Premium 集成:从 GA 中的未过滤视图导出数据时,如何在 bigQuery 中使用 IP 过滤器(以排除内部流量)

我可以以某种方式从java中的Collections.Min / Collections.Max中排除或过滤掉一个值吗?