SpringBoot3迁移:公共URL触发认证过滤器致401问题解决
问题解决:SpringBoot3中公共URL仍触发自定义认证过滤器
问题原因
你的CustomAuthenticationFilter标注了@Component注解,这会让Spring将它自动注册到Servlet全局过滤器链中,不受Spring Security配置的securityMatcher(protectedUrls)限制。也就是说,即使是公共URL(/api/auth/login、/api/auth/register),也会先经过这个全局过滤器,导致返回401。
解决方案
方案一:移除全局过滤器注册,仅在Security链中使用
- 去掉
CustomAuthenticationFilter类上的@Component注解 - 在
SecurityConfig中手动创建该过滤器的Bean,避免全局注册:
@Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) public class SecurityConfig { public static final RequestMatcher PUBLIC_URLS = new OrRequestMatcher( new AntPathRequestMatcher("/api/auth/login"), new AntPathRequestMatcher("/api/auth/register") ); // 手动创建CustomAuthenticationFilter Bean,注入依赖 @Bean public CustomAuthenticationFilter customAuthenticationFilter(UserCrudService userCrudService) { return new CustomAuthenticationFilter(userCrudService); } @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { var protectedUrls = new NegatedRequestMatcher(PUBLIC_URLS); http .securityMatcher(protectedUrls) .cors(cors -> cors.configurationSource(corsConfigurationSource())) .csrf(csrf -> csrf.disable()) .sessionManagement(sessionManagement -> sessionManagement.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .exceptionHandling(exceptionHandling -> exceptionHandling.authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.FORBIDDEN))) .authorizeHttpRequests(authorize -> authorize .requestMatchers("/api/data-transfer/**").hasAnyAuthority("ADMIN") .requestMatchers("/api/discount-code/**").hasAnyAuthority("USER") .anyRequest().authenticated()) .addFilterAfter(customAuthenticationFilter(userCrudService), BasicAuthenticationFilter.class); return http.build(); } @Bean public CorsConfigurationSource corsConfigurationSource() { [...] } }
同时修改CustomAuthenticationFilter的构造方法,注入UserCrudService:
public class CustomAuthenticationFilter extends OncePerRequestFilter { private static final String BEARER_PREFIX = "Bearer "; private final UserCrudService userCrudService; // 构造注入依赖 public CustomAuthenticationFilter(UserCrudService userCrudService) { this.userCrudService = userCrudService; } @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { [...] } }
方案二:在过滤器中添加忽略路径逻辑
如果不想移除@Component注解,可以重写OncePerRequestFilter的shouldNotFilter方法,指定公共URL不执行过滤逻辑:
@Component public class CustomAuthenticationFilter extends OncePerRequestFilter { private static final String BEARER_PREFIX = "Bearer "; @Autowired private UserCrudService userCrudService; // 重写该方法,判断请求是否为公共URL,是则跳过过滤 @Override protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException { return SecurityConfig.PUBLIC_URLS.matches(request); } @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { [...] } }
说明
两种方案都能解决问题:方案一从根源上避免全局过滤器干扰,更符合Spring Security的配置逻辑;方案二灵活调整过滤范围,适合需要保留全局过滤器但部分路径例外的场景。
内容的提问来源于stack exchange,提问作者Olek
相关产品推荐
相关产品推荐

