如何使用 Spring 的 Java 配置指定过滤器执行顺序?

Posted

技术标签:

【中文标题】如何使用 Spring 的 Java 配置指定过滤器执行顺序?【英文标题】:How to specify Filter execution order using Spring's Java Configuration? 【发布时间】:2014-01-05 21:53:09 【问题描述】:

我的初始化程序中有以下代码:

public class AppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer 

    @Override
    protected Filter[] getServletFilters() 

        DelegatingFilterProxy shiroFilter = new DelegatingFilterProxy("shiroFilter");
        shiroFilter.setTargetFilterLifecycle(true);

        return new Filter[]new CorsFilter(),shiroFilter;
    

我希望在ShiroFilter 之前执行CorsFilter。但是,Spring 文档并没有说过滤器的执行顺序是由它们在返回数组中的顺序决定的。

如果是这样,有人可以澄清一下吗?如果没有,有人可以建议我如何我保证过滤器的执行顺序?

【问题讨论】:

你的堆栈中哪里有OncePerRequestFilter “在哪里”是什么意思?它是春天的一部分 之前你在谈论 Shiro 的 OncePerRequestFilter。是哪一个? 完整阅读下面的 cmets。这个 cmets 也属于那个帖子本身,而不是这里。 web.xml 文件中的过滤器顺序已确定,如果您可以选择的话。 【参考方案1】:

过滤器注册在order of the array。

这导致ServletContext.addFilter() 按项目顺序被调用,然而,我不确定这是否真的导致容器按照它们注册的顺序执行过滤器。

例如,Tomcat 似乎使用 a HashMap to store filters,所以我不希望过滤器一定按照添加顺序运行。

Spring 确实提供了一个 org.springframework.web.filter.CompositeFilter,所以我只返回一个 CompositeFilter,其中包含您实际想要使用的两个过滤器。

【讨论】:

+1 我只是在研究如何使用CompositeFilter 执行此操作。创建一个 DelegatingFilterProxy,其中包含一个 CompositeFilter,您将要注册的 Filter bean 的 List 传递给该 Filter 您能否提供带有 CompositeFilter 的转换后的代码示例。这将使这个答案对未来的读者更好。 显然 CompositeFilter 不适用于任何使用 Apache Shiro 的 OncePerRequestFilter 的过滤器,因为它的 OncePerRequestFilter.doFilter() 方法检查过滤器是否已经按名称执行,并且在这种情况下名称变为'compositeFilter'(而不是执行过滤器),从而导致 OncePerRequestFilter 永远不会被执行。 看起来没有特别简单的方法可以做到这一点。由于 Servlet API (***.com/questions/6560969/…) 的限制,这个答案建议重新使用 XML。您还可以查看将 CompositeFilter 包装在 OncePerRequestFilter 中。或者也许只是继承 ShiroFilter 并直接调用 CorsFilter。 Tomcat 对HashMap 的使用是一个红鲱鱼:Filters 在 XML 中声明时以正确的顺序注册和执行,但 Filters 的顺序是通过发现和注册的无法控制注释。为此,您必须使用web.xml 或某种复合Filter【参考方案2】:

只是为了让问题保持最新。

使用弹簧@Order - Annotation

@Component(value = "myCorsFilter")
@Order(Ordered.HIGHEST_PRECEDENCE)
public class CorsFilter implements Filter 

    [...]



public class AppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer 

    @Override
    protected Class<?>[] getRootConfigClasses() 
        return new Class[]  AppConfiguration.class ;
    

    @Override
    protected Class<?>[] getServletConfigClasses() 
        return null;
    

    @Override
    protected String[] getServletMappings() 
        return new String[]  "/" ;
    

    @Override
    protected Filter[] getServletFilters() 
        return new Filter[]  
             new DelegatingFilterProxy("myEncodingFilter"), 
             new DelegatingFilterProxy("myCorsFilter"),    // or just new CorsFilter()
             new DelegatingFilterProxy("mySecurityFilter") //...
        ;
    


【讨论】:

【参考方案3】:

对于可能想要使用 javax 注释而不是 spring Order 的人,@javax.annotation.Priority 注释也可以用来代替 @Order,就像上面“dit”的答案一样。

【讨论】:

最好将此作为对 dit 答案的评论

以上是关于如何使用 Spring 的 Java 配置指定过滤器执行顺序?的主要内容,如果未能解决你的问题,请参考以下文章

Spring OAuth 过滤器链和 Java 配置

必须指定 Spring Security authenticationmanager - 用于自定义过滤器

JAVA WEB 过滤器(Filter)中向容器 Spring 注入 bean

Spring Security 3.0:如何指定应用自定义过滤器的 URL?

如何使用 Spring Session + Spring security xml 配置和多重安全过滤器

如何使用不同的身份验证过滤器配置两个 Spring 安全 http 元素?