如何在 XML 配置中将 Spring-Security AntPathRequestMatcher 配置为不区分大小写

How to configure Spring-Security AntPathRequestMatcher to case insensitive in XML configuration

我们最近将 Spring-Security 从 3.X 升级到 5.6。大多数问题我们都可以解决,但有一件事证明是困难的。该问题是由默认行为的更改引起的 (3.1 vs. 5.6) of the AntPathRequestMatcher (happened in Spring 4.2?)。

所以现在我们有了拦截器和过滤器,当使用不同的情况时它们不再被触发。

请注意:在旧版本中,与 spring 相关的所有内容都在 XML 中配置,现在必须保持这样。将来我们会将其更改为注释,但现在不会,因为由于应用程序的大小,这是一项艰巨的任务。

当前配置:

<bean class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor"
        id="filterSecurityInterceptor">
        <property name="securityMetadataSource">
            
            <security:filter-security-metadata-source>
                <security:intercept-url 
                    access="hasRole('ROLE_User')" pattern="/servlet/**"/>
                <security:intercept-url
                    access="hasRole('ROLE_User')" pattern="/mobile.html" />
                <security:intercept-url
                    access="hasAnyRole('ROLE_User', 'ROLE_OtherUser', 'ROLE_Guest')"
                pattern="/offlineAssets/*" />
                ...

filter-security-metadata-source 的配置中,可以使用 request-matcher="ant" 配置不同的匹配器,但是我没有找到像以前那样使用不区分大小写的 AntMatcher 的方法。有一个 ticket 讨论引入一个 ciAnt 匹配器,但显然没有完成,因为它在当前的 spring-security 版本中不可用。

一种可能是在 intercept-url 级别上定义一个 request-matcher-ref,但是我必须为每个规则定义一个匹配器 bean(并且有很多这样的规则)。这会使整个文件膨胀并且可读性会受到影响。不幸的是,将所有内容都转换为 ciRegex 也不是一种选择。必须有更简单的方法来做到这一点。

配置的过滤器链也有类似的情况,但是我们可以通过实现我们自己的 SecurityFilterChain class 来解决问题,它会创建一个不区分大小写的匹配器,并且可以在XML 配置。然而,这对于 intercept-urls 是不可能的(我们未能构建 Map<RequestMatcher, Collection<ConfigAttribute>> requestMap

那么知道如何配置不区分大小写的 AntPathRequestMatcher 吗?

我想知道为什么你反对在你的 XML beans 配置中更冗长,因为这是自 1.x 版本以来 Spring 的工作方式,直到Java Config 已在生态系统中提升。我知道您正在管理一个大型应用程序,添加一些东西会使您的配置可维护性变得复杂。

一种方法(我认为你最好的选择)是添加 request-matcher-ref 和扩展 bean,它是 Spring antMatcher 的不敏感版本。

另一种方式可能是这些: 也许您可以在请求堆栈中实现自定义安全过滤器,并在其中检查自定义的不敏感 antMatcher 是否匹配。这些方式可以大大简化您的配置任务。

一些技巧,虽然不直接相关但对管理大型配置很有用 Spring Beans XML 文件:

1/ 您可以将 XML 配置拆分到模块专用文件中,以便更好地维护,并将它们导入主 XML 文件中,该文件绑定到您的 web 应用程序 Spring 上下文。

2/ 您可以一步步添加一些Java配置,简化您的日常维护工作。

3/ 您可以将属性文件中的所有 beans 字段初始化值外部化,并使用 @Profile 注释通过自定义 Spring 配置文件获取它们的值(dev、qa、prod 是开发期间的常用配置文件process) 和 @Value 注释来获取 POJO 中的值。 => Beans 初始化将放在 XML 配置之外,随着您的进步,它会越来越轻。

正如我最初 post 中所建议的,我能想到的唯一方法是定义我们自己的 matcher-beans。现在这意味着添加大量 two-digit 的新 bean 定义会使我们的 XML 配置膨胀:

<bean class="org.springframework.security.web.util.matcher.AntPathRequestMatcher" id="antmatcherServlet">
    <constructor-arg value="/servlet/**" index="0"/>
    <constructor-arg index="1"><null/></constructor-arg>
    <constructor-arg value="false" index="2"/>
</bean>
<bean class="org.springframework.security.web.util.matcher.AntPathRequestMatcher" id="antmatcherMobile">
    <constructor-arg value="/mobile.html" index="0"/>
    <constructor-arg index="1"><null/></constructor-arg>
    <constructor-arg value="false" index="2"/>
</bean>
...

而参考是这样完成的:

        <security:filter-security-metadata-source>
            <security:intercept-url 
                access="hasRole('ROLE_User')" request-matcher-ref="antmatcherServlet"/>
            <security:intercept-url
                access="hasRole('ROLE_User')" request-matcher-ref="antmatcherMobile"/>
            <security:intercept-url
                access="hasAnyRole('ROLE_User', 'ROLE_OtherUser', 'ROLE_Guest')"
            request-matcher-ref= "..." />
            ...

像这样的解决方案真的很棒而且不会破坏向后兼容性:

3.X:

<security:filter-security-metadata-source request-matcher="ant">

4.X、5.X

<security:filter-security-metadata-source request-matcher="ciAnt">