Spring Security 6 未认证端点配置失效,请求返回401未授权
Spring Boot 3.0.1 + Spring Security 6.0 公共端点返回401问题解决
问题场景
升级Spring Boot至3.0.1、Spring Security至6.0版本后,配置为无需认证的公共端点(如/rest/public/export/)调用时始终返回401未认证。已按照官方指南移除WebSecurityConfigurerAdapter,当前Security配置如下:
@EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true) public class SecurityConfig { @Value("${auth0.audience}") private String audience; @Value("${spring.security.oauth2.resourceserver.jwt.issuer-uri}") private String issuer; @Bean JwtDecoder jwtDecoder() { NimbusJwtDecoder jwtDecoder = (NimbusJwtDecoder) JwtDecoders.fromOidcIssuerLocation(issuer); OAuth2TokenValidator<Jwt> audienceValidator = new AudienceValidator(audience); OAuth2TokenValidator<Jwt> withIssuer = JwtValidators.createDefaultWithIssuer(issuer); OAuth2TokenValidator<Jwt> withAudience = new DelegatingOAuth2TokenValidator<>(withIssuer, audienceValidator); jwtDecoder.setJwtValidator(withAudience); return jwtDecoder; } @Bean public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception { return httpSecurity .csrf(csrf -> csrf.disable()) .authorizeHttpRequests(auth -> auth .requestMatchers("/rest/public/**").permitAll() .anyRequest().authenticated() ) .sessionManagement(sess -> sess.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt) .build(); } }
调用日志显示请求被标记为匿名,但仍被拦截:
o.s.security.web.FilterChainProxy : Securing GET /rest/public/export/ o.s.s.w.a.AnonymousAuthenticationFilter : Set SecurityContextHolder to anonymous SecurityContext o.s.s.w.s.HttpSessionRequestCache : Saved request http://localhost:8090/rest/public/export/?continue to session
问题原因
- 无状态模式下请求缓存冲突:配置了
SessionCreationPolicy.STATELESS但未禁用默认的HttpSessionRequestCache,该缓存尝试将请求保存到session,但无状态模式下session不存在,导致认证流程异常。 - 方法级安全注解干扰:若公共端点的控制器方法添加了
@PreAuthorize等方法级安全注解,即使HttpSecurity配置了permitAll,方法级校验仍会要求认证。 - 路径匹配细节问题:Spring Security 6的路径匹配默认对尾斜杠敏感,若请求路径带尾斜杠而匹配规则未覆盖,可能导致匹配失败。
解决方案
1. 调整SecurityFilterChain配置
禁用请求缓存并配置异常处理,确保无状态模式下正常返回401而非触发无效的session操作:
@Bean public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception { return httpSecurity .csrf(csrf -> csrf.disable()) .authorizeHttpRequests(auth -> auth // 确保路径匹配覆盖带/不带尾斜杠的情况 .requestMatchers("/rest/public/**", "/rest/public/**/").permitAll() .anyRequest().authenticated() ) .sessionManagement(sess -> sess.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt) // 禁用请求缓存,适配无状态模式 .requestCache(requestCache -> requestCache.nullRequestCache()) // 配置异常处理,直接返回401错误 .exceptionHandling(exceptions -> exceptions .authenticationEntryPoint((request, response, authException) -> { response.sendError(HttpServletResponse.SC_UNAUTHORIZED, authException.getMessage()); }) ) .build(); }
2. 检查控制器方法注解
移除公共端点控制器方法上的@PreAuthorize、@Secured等强制认证的注解,确保HttpSecurity的permitAll生效。
3. 验证路径匹配规则
若仍存在匹配问题,可显式配置路径匹配策略为非严格模式:
@Bean public PathMatcher pathMatcher() { AntPathMatcher matcher = new AntPathMatcher(); matcher.setTrimTokens(false); matcher.setCaseSensitive(false); return matcher; }
验证
修改配置后重启服务,再次调用公共端点,应正常返回业务响应而非401。
内容的提问来源于stack exchange,提问作者Stuzfuz
相关产品推荐
相关产品推荐

