Spring Boot 3.1.4配置permitAll后请求仍过JwtFilter的问题
问题:Spring Boot 3.1.4中配置permitAll路径仍被过滤器拦截
在Spring Boot 3.1.4中,我已配置允许所有请求访问/auth/login路径,但实际请求仍会经过JwtFilter和AuthorizationFilter,最终返回403。
配置代码
package com.example.demo.Auth; import org.springframework.beans.factory.annotation.Autowired; 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.configurers.AbstractHttpConfigurer; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; @Configuration public class AuthConfig { @Autowired private JwtFilter jwtFilter; @Bean public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception { return httpSecurity .addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class) .authorizeHttpRequests(authorizationManagerRequestMatcherRegistry -> { authorizationManagerRequestMatcherRegistry.requestMatchers("/auth/registration").permitAll(); authorizationManagerRequestMatcherRegistry.requestMatchers("/auth/login").permitAll(); authorizationManagerRequestMatcherRegistry.anyRequest().authenticated(); }) .httpBasic(AbstractHttpConfigurer::disable) .csrf(AbstractHttpConfigurer::disable) .build(); } }
请求示例
POST localhost:8080/auth/login Content-Type: application/json { "userName": "jane_doe", "password": "pw12345789" }
预期与实际结果
- 预期:请求应通过并由控制器处理
- 实际:请求仍会经过jwtFilter和AuthorizationFilter,最终返回403
疑问
为何已配置绕过该路径的请求仍会经过过滤器?
解决说明
核心原因:permitAll()仅表示该路径无需身份认证授权,但不会跳过Spring Security过滤器链中的自定义过滤器。你通过addFilterBefore添加的JwtFilter是全局生效的,会拦截所有请求,包括配置了permitAll的路径。
以下两种方案可解决此问题:
方案一:在JwtFilter内部判断路径直接放行
修改JwtFilter的doFilterInternal方法,添加路径判断逻辑,匹配到无需验证的路径时直接放行:
@Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String requestUri = request.getRequestURI(); // 跳过登录、注册路径的JWT验证 if ("/auth/login".equals(requestUri) || "/auth/registration".equals(requestUri)) { filterChain.doFilter(request, response); return; } // 原有JWT验证逻辑 // ... }
方案二:配置多SecurityFilterChain分离路径处理
通过定义多个SecurityFilterChain并指定执行顺序,让无需认证的路径走单独的过滤器链,不加载JwtFilter:
@Configuration public class AuthConfig { @Autowired private JwtFilter jwtFilter; // 第一个过滤器链:处理/auth开头的路径,无需认证,不加载JwtFilter @Bean @Order(1) public SecurityFilterChain publicSecurityFilterChain(HttpSecurity http) throws Exception { return http .securityMatcher("/auth/**") .authorizeHttpRequests(auth -> auth.anyRequest().permitAll()) .csrf(AbstractHttpConfigurer::disable) .httpBasic(AbstractHttpConfigurer::disable) .build(); } // 第二个过滤器链:处理其他所有路径,需要认证,加载JwtFilter @Bean @Order(2) public SecurityFilterChain privateSecurityFilterChain(HttpSecurity http) throws Exception { return http .securityMatcher("/**") .authorizeHttpRequests(auth -> auth.anyRequest().authenticated()) .addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class) .csrf(AbstractHttpConfigurer::disable) .httpBasic(AbstractHttpConfigurer::disable) .build(); } }
Spring Security会按@Order注解的顺序匹配过滤器链,/auth/login会被第一个链处理,直接放行到控制器,不会经过JwtFilter。
内容的提问来源于stack exchange,提问作者Ero Stefano
相关产品推荐
相关产品推荐

