更新到 Spring Security 5.8.6 后 JBoss 上的 Spring 请求匹配器问题

Spring request matcher issue on JBoss after update to Spring Security 5.8.6

提问人:Plantexchen 提问时间:8/30/2023 最后编辑:Plantexchen 更新时间:10/20/2023 访问量:2903

问:

从 Spring Security 5.8.2 升级到 5.8.6 后,我在 JBoss EAP 7.4 上的部署遇到了问题(它在嵌入式 Tomcat 上工作正常)。我收到以下错误消息:

此方法无法确定这些模式是否为 Spring MVC 模式与否。如果此端点是 Spring MVC 端点,请使用 requestMatchers(MvcRequestMatcher);否则,请使用 requestMatchers(AntPathRequestMatcher)。

这是因为 servlet 上下文:{org.apache.jasper.servlet.JspServlet=[*.jsp, .jspx], javax.faces.webapp.FacesServlet=[/faces/, *.jsf, *.faces, *.xhtml], org.springframework.web.servlet.DispatcherServlet=[/]}。

对于每个 MvcRequestMatcher,将 MvcRequestMatcher#setServletPath 调用到 指示 servlet 路径。

我该如何解决这个问题?我们只有由 @Controller 注释的控制器,没有自定义 servlet。我的安全配置基本上如下:

@Configuration
@EnableWebSecurity
@EnableMethodSecurity(securedEnabled = true)
public class MySecurityConfig
{
    @Bean
    MvcRequestMatcher.Builder mvc(HandlerMappingIntrospector introspector)
    {
        return new MvcRequestMatcher.Builder(introspector);
    }


    @Bean
    public SecurityFilterChain filterChain(HttpSecurity httpSecurity, MvcRequestMatcher.Builder mvc) throws Exception
    {
       return httpSecurity
                .authorizeHttpRequests(auth ->
                        auth.requestMatchers(HttpMethod.OPTIONS)
                                .permitAll()
                                .requestMatchers(
                                        mvc.pattern("/my-public-controller-1/**"),
                                        mvc.pattern("/my-public-controller-2/**"),
                                        mvc.pattern("/my-public-controller-3/**"))
                                .permitAll()
                                .anyRequest()
                                .authenticated())
                .build();
    }
}

我们使用 JBoss 默认配置。有一个和一个.最后一个文件如下所示:jboss-web.xmljboss-deployment-structure.xml

<jboss-deployment-structure>
    <deployment>
        <dependencies>
            <module name="com.sun.xml.bind"/>
        </dependencies>
        <exclude-subsystems>
            <subsystem name="jaxrs"/>
            <subsystem name="logging"/>
        </exclude-subsystems>
    </deployment>
</jboss-deployment-structure>

我试图像这样玩弄请求匹配器,但它没有帮助。

    public SecurityFilterChain filterChain(HttpSecurity httpSecurity, MvcRequestMatcher.Builder mvc) throws Exception
    {
        return httpSecurity
                .authorizeHttpRequests(auth ->
                        auth.requestMatchers(HttpMethod.OPTIONS)
                                .permitAll()
                                .requestMatchers(
                                        mvc.pattern("/my-public-controller-1/**"),
                                        mvc.pattern("/my-public-controller-2/**"),
                                        mvc.pattern("/my-public-controller-3/**"),
                                        antMatcher("/faces/*"))
                                .permitAll()
                                .anyRequest()
                                .authenticated())
                .build();
    }

我试图将 Faces 排除在外,但这一步毁了一切:jboss-deployment-structure.xml

<jboss-deployment-structure>
    <deployment>
        <dependencies>
            <module name="com.sun.xml.bind"/>
        </dependencies>
        <exclude-subsystems>
            <subsystem name="jaxrs"/>
            <subsystem name="logging"/>
        </exclude-subsystems>
        <exclusions>
            <module name="javax.faces.api" slot="main"/>
        </exclusions>
    </deployment>
</jboss-deployment-structure>

我在这里看到了一个类似的问题,但我无法从中找到可行的解决方案:https://github.com/spring-projects/spring-security/issues/13568

顺便说一句,我们使用默认的servlet路径,所以错误消息中的这个建议对我来说毫无意义:

对于每个 MvcRequestMatcher,将 MvcRequestMatcher#setServletPath 调用到 指示 servlet 路径使

尽管如此,我还是尝试了类似的东西,但这也没有帮助:

    @Bean
    MvcRequestMatcher.Builder mvc(HandlerMappingIntrospector introspector)
    {
        return new MvcRequestMatcher.Builder(introspector).servletPath("");
    }
Spring Security JBoss Wildfly

评论

0赞 Plantexchen 8/31/2023
好的,作为临时解决方案,我从Spring Security 5.8.6切换到5.7.10。我希望他们能在不久的将来找到更好的解决方案。关于这种新的匹配行为有很多抱怨:github.com/spring-projects/spring-security/issues/13568

答:

0赞 joninx 9/27/2023 #1

我的 SecurityConfig 如下所示:

package com.mycompany.ws.config

import org.apache.logging.log4j.LogManager
import org.apache.logging.log4j.Logger
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.config.annotation.web.builders.WebSecurity
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer
import org.springframework.security.web.SecurityFilterChain
import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher
import org.springframework.web.servlet.handler.HandlerMappingIntrospector


@Configuration
@EnableWebSecurity
class SecurityConfig {

    @Bean
    fun webSecurityCustomizer(
        introspector: HandlerMappingIntrospector,
    ): WebSecurityCustomizer {
        val mvcMatcherBuilder = MvcRequestMatcher.Builder(introspector)
        return WebSecurityCustomizer { web: WebSecurity ->
            web.ignoring() // Spring Security should completely ignore URLs starting with /resources/ and so forth
                .requestMatchers(
                    mvcMatcherBuilder.pattern("/resources/**"),
                    mvcMatcherBuilder.pattern("/static/**"),
                    mvcMatcherBuilder.pattern("/css/**"),
                    mvcMatcherBuilder.pattern("/js/**"),
                    mvcMatcherBuilder.pattern("/img/**"),
                    mvcMatcherBuilder.pattern("/lib/**"),
                    mvcMatcherBuilder.pattern("/favicon.ico")
                )
        }
    }

    @Bean
    @Throws(Exception::class)
    fun securityFilterChain(
        http: HttpSecurity,
    ): SecurityFilterChain {
        return http
            .authorizeHttpRequests { cfg ->
                cfg.anyRequest().permitAll()
            }
            .csrf { it.disable() }
            .cors { it.disable() }
            .formLogin { it.disable() }
            .build()
    }

    companion object {
        val log: Logger = LogManager.getLogger(this::class.java)
    }
}
0赞 Tirath 10/20/2023 #2

所以你在 Wildfy 上。在 web-inf 下添加 jboss-deployment-structure.xml 文件,你应该可以开始了。

enter image description here

<?xml version="1.0" encoding="UTF-8"?>
<jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.2">
    <deployment>
        <exclude-subsystems>
            <subsystem name="logging" />
            <subsystem name="jsf" />
        </exclude-subsystems>
    </deployment>
</jboss-deployment-structure>

我在 Wildfly 27.0.1 上使用 Spring Boot 3.1JDK 17

根据错误消息 - 类路径上有 3 个 servlet。DispatcherSpring Boot 提供,另外 2 个由 WildflyJSFJSP 提供。

通过添加此文件,我们告诉应用程序服务器 - 不要在我的应用程序类路径上添加 JSF servlet。

可以在独立的 .xml 文件中检查子系统名称。

enter image description here

因为我在独立的 .xml 中注释了 jsp-configorg.apache.jasper.servlet.JspServlet=[*.jsp, .jspx]

enter image description here