如何从 Spring Security 中的默认过滤器堆栈中删除一个过滤器?

Posted

技术标签:

【中文标题】如何从 Spring Security 中的默认过滤器堆栈中删除一个过滤器?【英文标题】:How to delete one filter from default filter stack in Spring Security? 【发布时间】:2012-12-23 15:32:34 【问题描述】:

我必须从 Spring Security 堆栈中排除一个默认过滤器。所以所有过滤器都应该像往常一样工作。看来我找到了这样做的方法,制作自定义FilterChainProxy:

public class CustomFilterChainProxy extends FilterChainProxy 

Logger LOGGER = Logger.getLogger(CustomFilterChainProxy.class);

public CustomFilterChainProxy() 
    super();
    LOGGER.debug("Run custom filter proxy");
    LOGGER.debug("String filters: " + this.toString());


public CustomFilterChainProxy(SecurityFilterChain chain) 
    super(chain);
    LOGGER.debug("Run custom filter proxy with chains");


如您所见,它具有获取过滤器列表的构造函数,因此我将能够根据需要从链中删除一个过滤器,其余的将照常工作。但是我不能为这样的构造函数在安全配置中制作 bean。如果我使用

<bean id="filterChainProxy" class="com.pkg.CustomFilterChainProxy">

当然,使用默认构造函数构建对象。好的,我尝试使用一些过滤器列表制作 bean:

<bean id="filterChainProxy" class="ru.olekstra.backoffice.util.CustomFilterChainProxy">
<constructor-arg>
    <list>
        <sec:filter-chain pattern="/**" 
        filters="BasicUserApprovalFilter" />
    </list>
</constructor-arg>
</bean>

但这不会编译,因为 BasicUserApprovalFilter 是未知 bean。那么如何从默认过滤器堆栈中排除一个过滤器呢?如果我使用自定义过滤器链代理的方式是一个不错的决定,那么如何使用默认过滤器链创建 bean?

【问题讨论】:

【参考方案1】:

如果您提供更多关于您要删除的过滤器以及原因的详细信息,这可能会有所帮助。

如果您愿意,可以在创建过滤器链后使用BeanPostProcessor 修改过滤器链。在默认命名空间配置中,您可以为 &lt;http&gt; 元素创建的过滤器链命名:

<http name="myFilterChain">
   ...

这将使用此名称注册SecurityFilterChain 类型的bean。 FilterChainProxy 是根据这些列表创建的。

后处理器看起来像:

public class SecurityFilterChainPostProcessor implements BeanPostProcessor 

    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException 

        if (beanName.equals("myFilterChain")) 
            DefaultSecurityFilterChain fc = (DefaultSecurityFilterChain)bean;
            List<Filter> filters = fc.getFilters();

            // Modify the filter list as you choose here.                
            List<Filter> newFilters = ...

            return new DefaultSecurityFilterChain(fc.getRequestMatcher(), newFilters);
        

        return bean;
    

    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException 
        return bean;
    

然后只需在您的应用程序上下文中注册这个 bean 的一个实例,其余的由 Spring 完成。这样您就可以避免将所有 Spring Security 基础结构过滤器定义为单独的 bean。

更新

这是real-world example 和its configuration 的链接。

【讨论】:

我有这样的问题:***.com/questions/14019472/… 经过长时间的搜索,我发现请求缓存由 EXCEPTION_TRANSLATION_FILTER 执行,因此作为缓存问题的决定,我想排除过滤器。如果它有助于春季项目,我可以描述更多关于缓存问题的信息。 请展示如何正确设置 ,因为它在我这边不起作用(我只是添加了这个字符串并得到错误:发现无效的内容从元素开始'http'.),看来我需要更详细的手册来将此 bean 添加到我的配置中。 命名空间配置在参考手册中有完整的解释,你会发现很多关于 SO 的例子。 “name”属性仅适用于 3.1+,因此请确保您使用的是最新的 XML 模式(再次复制手册中的示例)。 删除ExceptionTranslationFilter 是个坏主意。我已经在另一个帖子里回复了。如果您不想使用缓存请求,只需将身份验证配置为始终使用默认目标 URL。 卢克,在其他线程中,我写了我是如何解决这个问题的。但就我而言,我只想测试这个有趣的代码示例。我按照你写的那样实现了它,在循环中我将过滤器中的所有元素传递给 newFilters,除了第一个,添加一些调试消息,但在日志中仍然触发了所有 11 个过滤器(但它应该只有 10 个,因为我删除了一个过滤器) .此新调用也没有记录器(log4j)消息。要查看过滤器列表,我使用我在其他线程中描述的情况(登录后从缓存中获取旧请求)。能告诉我有什么问题吗?【参考方案2】:

您可以通过 SpringSecurity 配置中的 filter-chain-map 标签定义自己的过滤器链:

<bean id="springSecurityFilterChain" class="org.springframework.security.web.FilterChainProxy">
    <security:filter-chain-map>
       <sec:filter-chain pattern="/**"
            filters="
        ConcurrentSessionFilterAdmin, 
        securityContextPersistenceFilter, 
        logoutFilterAdmin, 
        .....
        anonymousAuthenticationFilter, 
        sessionManagementFilterAdmin, 
        exceptionTranslationFilter, 
        filterSecurityInterceptorAdmin,
        MonitoringFilter"/> 
    </security:filter-chain-map>
</bean>

【讨论】:

我尝试过这个变体,但它似乎不起作用:我留下了列表中写的过滤器 7 过滤器,但在日志中我看到触发了所有 11 个默认过滤器:(FilterChainProxy.java:doFilter :318) /project/path 位于附加过滤器链中 11 的位置 1;触发过滤器:'SecurityContextPersistenceFilter', ..., (FilterChainProxy.java:doFilter:318) /project/path 位于附加过滤器链中 11 的第 11 位;触发过滤器:“FilterSecurityInterceptor”。所以什么都没有改变。 你的 web.xml 中是否有 springSecurityFilterChain 用于 DelegatingFilterProxy?你使用 配置元素吗? 是的,我有这样的代码: springSecurityFilterChainorg.springframework.web.filter.DelegatingFilterProxy in web. xml 并在 spring 安全配置中使用 http 元素。 尝试调试 DelegatingFilterProxy.initDelegate(...) 方法。看起来应用程序 sturtup DelegatingFilterProxy 采用由 元素准备的默认过滤器链而不是自定义过滤器链。 我不确定您是否可以同时使用 和自定义过滤器链。对我来说,如果您定义了自定义过滤器链,那么您需要手动提供 元素提供的其余 bean(请参阅this example、filterChainProxy 和 filterInvocationInterceptor bean)。如果您绝对想使用 元素,那么最好使用@Luke Taylor 提供的 BeanPostProcessor 解决方案

以上是关于如何从 Spring Security 中的默认过滤器堆栈中删除一个过滤器?的主要内容,如果未能解决你的问题,请参考以下文章

如何从 Spring Security 中的会话管理(超时/并发检查)中排除某些页面?

如何从 Spring Security 中的 java 代码登录用户?

Spring Security教程:自定义表结构

如何在spring security java config中通过jsp表单更新用户详细信息

Spring Security教程:自定义数据库查询

如何从 Grails 中的 Spring Security 获取普通密码或解密密码?