深入解析 Spring Security 配置中的 CSRF 启用与 requestMatchers 报错问题

1,013 阅读3分钟

深入解析 Spring Security 配置中的 CSRF 启用与 requestMatchers 报错问题

最近在配置 Spring Security 的过程中,有小伙伴遇到了关于 CSRF 启用与路径匹配器 requestMatchers 的相关问题。本文将从问题的根源出发,分析 Spring Security 不同版本中的变化,同时提供详细的解决方案。希望这篇博客能帮助大家快速解决类似问题,并深入理解 Spring Security 的相关机制。

image.png

问题 1:CSRF 的启用方法报错

背景: 在 Spring Security 的配置中,很多开发者会禁用 CSRF(跨站请求伪造)保护以方便调试或快速开发:

http.csrf(csrf -> csrf.disable());

后来开发者发现需要重新启用 CSRF 时,尝试使用如下代码:

http.csrf(csrf -> csrf.enable());

报错信息

无法解析 'CsrfConfigurer' 中的方法 'enable'

原因分析: Spring Security 的 CsrfConfigurer 类中并没有提供 enable() 方法。事实上,Spring Security 默认是启用 CSRF 的,因此并不需要显式地调用 enable() 方法。

解决方案

如果之前禁用了 CSRF,现在需要重新启用,只需要移除 .csrf(csrf -> csrf.disable()) 配置即可。默认情况下,CSRF 是开启的。

具体配置代码如下:

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    http
        .csrf() // 保持默认的 CSRF 启用状态
        .and()
        .authorizeHttpRequests(auth -> auth
            .requestMatchers("/login", "/api/users/register", "/error").permitAll()
            .anyRequest().authenticated()
        );
    return http.build();
}

注意:如果需要对某些路径禁用 CSRF,可以通过 ignoringRequestMatchers() 方法实现:

.csrf(csrf -> csrf
    .ignoringRequestMatchers("/api/ignore-csrf")
)

问题 2:requestMatchers 多路径匹配报错

背景: 开发者尝试配置路径权限时,使用了 requestMatchers 方法,并传入多个路径进行匹配:

.authorizeHttpRequests(auth -> auth
    .requestMatchers("/login", "/api/users/register", "/error", "/css/**", "/js/**", "/images/**").permitAll()
    .anyRequest().authenticated()
)

报错信息

无法解析方法 'requestMatchers(String, String, String, String, String, String)'

原因分析: 在 Spring Security 6.x 中,requestMatchers() 方法的签名发生了变化,不再支持传入多个字符串参数。这种变化是为了提升灵活性,同时统一方法行为。

在 Spring Security 6.x 中,requestMatchers() 方法的典型用法如下:

  1. 接收单个路径:

    .requestMatchers("/login")
    
  2. 接收 RequestMatcher 类型的对象:

    .requestMatchers(new AntPathRequestMatcher("/css/**"))
    

因此,传入多个字符串路径的方式在新版中不被支持了。

解决方案

方案 1:分多次调用 requestMatchers()

最直接的方法是将每个路径分开调用 requestMatchers()

.authorizeHttpRequests(auth -> auth
    .requestMatchers("/login", "/api/users/register", "/error").permitAll()
    .requestMatchers("/css/**", "/js/**", "/images/**").permitAll()
    .anyRequest().authenticated()
)
方案 2:自定义匹配器

如果需要对多个路径进行集中匹配,可以通过 RequestMatcher 实现更复杂的逻辑。例如:

.authorizeHttpRequests(auth -> auth
    .requestMatchers(new OrRequestMatcher(
        new AntPathRequestMatcher("/login"),
        new AntPathRequestMatcher("/api/users/register"),
        new AntPathRequestMatcher("/error"),
        new AntPathRequestMatcher("/css/**"),
        new AntPathRequestMatcher("/js/**"),
        new AntPathRequestMatcher("/images/**")
    )).permitAll()
    .anyRequest().authenticated()
)
方案 3:降级使用 antMatchers()(仅适用于 Spring Security 5.x)

在 Spring Security 5.x 中,仍然可以使用 antMatchers() 方法,该方法支持多个路径参数:

.authorizeRequests()
    .antMatchers("/login", "/api/users/register", "/error", "/css/**", "/js/**", "/images/**").permitAll()
    .anyRequest().authenticated();

Spring Security 版本的兼容性提示

  1. Spring Security 5.x

    • 推荐使用 antMatchers() 配置路径权限。
    • 可以直接传入多个字符串路径参数。
  2. Spring Security 6.x

    • 推荐使用 requestMatchers()
    • 传入路径时需要单独调用或使用 RequestMatcher 组合。

要解决这些问题,建议先检查你的项目依赖中 Spring Security 的版本。如果使用 Spring Boot,请查看 spring-boot-starter-security 的版本。

通过如下方式确认 Spring Security 版本:

./mvnw dependency:tree | grep spring-security

总结

在 Spring Security 的升级过程中,API 的调整往往会带来一些配置上的困惑。尤其是在 Spring Security 6.x 中,requestMatchers 方法的变更使得原有配置可能会报错。

本文总结了以下关键点:

  1. Spring Security 默认启用了 CSRF,无需显式调用 enable() 方法。
  2. requestMatchers() 方法在 Spring Security 6.x 中签名发生变化,需根据新版的 API 规范进行调整。
  3. 在升级到 Spring Security 6.x 前,建议先了解主要 API 的变化,并对现有代码进行兼容性调整。