You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Security 6.3.3 permitAll失效:自定义/login接口返回401

问题:Spring Security 6.3.3中自定义/login接口无法绕过认证返回401

问题背景

原有基于Spring Security 6.0.1的Spring Boot应用中,AUTH_WHITELIST内的所有接口均可正常免认证访问。但升级到6.3.3版本后,Swagger相关接口仍正常,自定义的/login/username等接口却返回401未授权错误,即使这些路径已加入白名单。

6.0.1版本配置

@Configuration
@EnableWebSecurity
@EnableMethodSecurity
@RequiredArgsConstructor
@EnableWebMvc
public class SecurityConfig {

    private static final String[] AUTH_WHITELIST = {
            "/v3/api-docs/**",
            "/actuator/**",
            "/swagger-ui/**",
            "/login**",
            "/error**"
    };
    
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    
        http.cors()
                .and().csrf().disable()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeRequests()
                .requestMatchers(AUTH_WHITELIST).permitAll()
                .anyRequest().permitAll()
        ;
    
        return http.build();
    }

}

6.3.3版本配置

@Configuration 
@EnableWebSecurity 
@EnableMethodSecurity 
@RequiredArgsConstructor 
@EnableWebMvc 
public class SecurityConfig {

    private static final String[] AUTH_WHITELIST = {
            "/v3/api-docs/**",
            "/actuator/**",
            "/swagger-ui/**",
            "/login**",
            "/error**"
    };
    
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception{
        http
                .csrf(AbstractHttpConfigurer::disable)
                .authorizeHttpRequests((authorize) -> authorize
                        .dispatcherTypeMatchers(DispatcherType.FORWARD, DispatcherType.ERROR).permitAll()
                        .requestMatchers(AUTH_WHITELIST).permitAll()
                        .anyRequest().authenticated()
                )
                .httpBasic(Customizer.withDefaults())
                .formLogin(AbstractHttpConfigurer::disable)
        ;
        return http.build();
    }

}

LoginController代码(未变更)

@Slf4j
@RestController
@RequestMapping("/login")
@Tag(name = "Login")
public class LoginController {

    @Autowired
    private LoginService service;
    
    @Autowired
    private UserLoginService userService;
    
    
    @PostMapping("/username")
    @Operation(summary = "Login", method = "POST")
    public ResponseEntity<LoginResponse> login(@RequestBody LoginRequest request, HttpServletRequest servletRequest) {
    
        LoginResponse dto = service.login(request, servletRequest);
        return ResponseEntity.ok(dto);
    }
    
    @PostMapping("/signup")
    @Operation(summary = "Sign Up", method = "POST")
    public ResponseEntity<UserLoginDto> signUp(@RequestBody SignUpRequest request, HttpServletRequest servletRequest) {
    
        UserLoginDto dto = userService.create(request, servletRequest);
        return ResponseEntity.ok(dto);
    }

}

问题原因与解决方法

核心问题:路径匹配规则错误

你的AUTH_WHITELIST中配置的/login**无法正确匹配/login/username这类带斜杠的子路径。Spring Security 6.x对路径匹配的规则更严格:

  • **用于匹配多级路径,但/login**的写法仅能匹配以/login开头且后续无斜杠的路径(如/login、/login123);
  • 要匹配/login下的所有子路径,必须写成/login/**。

另外,旧版本中你设置了.anyRequest().permitAll(),即使路径匹配有误,所有请求仍会被放行;但新版本改为.anyRequest().authenticated(),未匹配白名单的请求会触发认证校验,因此返回401。

修正步骤

  1. 修改白名单路径
    将AUTH_WHITELIST中的/login**替换为/login/**:
private static final String[] AUTH_WHITELIST = {
        "/v3/api-docs/**",
        "/actuator/**",
        "/swagger-ui/**",
        "/login/**",
        "/error**"
};
  1. 恢复无状态会话配置(推荐)
    旧版本中启用了无状态会话,新版本缺失该配置,对于REST接口建议添加回去,避免创建不必要的会话:
.httpBasic(Customizer.withDefaults())
.formLogin(AbstractHttpConfigurer::disable)
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
  1. 补全CORS配置(可选)
    如果应用需要支持跨域,恢复旧版本中的CORS配置:
.cors(Customizer.withDefaults())

修正后的完整配置

@Configuration
@EnableWebSecurity
@EnableMethodSecurity
@RequiredArgsConstructor
@EnableWebMvc
public class SecurityConfig {

    private static final String[] AUTH_WHITELIST = {
            "/v3/api-docs/**",
            "/actuator/**",
            "/swagger-ui/**",
            "/login/**",
            "/error**"
    };
    
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception{
        http
                .cors(Customizer.withDefaults())
                .csrf(AbstractHttpConfigurer::disable)
                .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                .authorizeHttpRequests((authorize) -> authorize
                        .dispatcherTypeMatchers(DispatcherType.FORWARD, DispatcherType.ERROR).permitAll()
                        .requestMatchers(AUTH_WHITELIST).permitAll()
                        .anyRequest().authenticated()
                )
                .httpBasic(Customizer.withDefaults())
                .formLogin(AbstractHttpConfigurer::disable);
        return http.build();
    }

}

验证

修改后重启应用,测试/login/username和/login/signup接口,应能正常返回200状态码,无需认证。

内容的提问来源于stack exchange,提问作者Hafiz Hisbullah

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 10:20:10