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

Spring Boot中自定义AuthenticationFilter与permitAll冲突问题排查

问题分析与解决方案

核心概念错误

你混淆了过滤器执行时机和授权规则执行时机的顺序:

  • Spring Security的过滤器链是在授权规则之前执行的。只要请求匹配了当前SecurityFilterChain的securityMatcher("/api/v1/**")范围,不管后续配置了permitAll,自定义的JwtTokenAuthenticationFilter都会被触发执行。
  • 你的/api/v1/test/hola属于/api/v1/**的匹配范围,所以过滤器会先拦截该请求并执行认证逻辑,导致未授权问题,而授权规则的permitAll是在过滤器执行之后才生效的,根本没机会跳过认证。

实现自定义过滤器仅应用于部分端点的方案

方案1:在自定义过滤器内部添加跳过逻辑

直接在JwtTokenAuthenticationFilter的doFilter方法中,判断请求路径是否属于无需认证的范围,若是则直接放行,不执行认证逻辑:

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    HttpServletRequest httpRequest = (HttpServletRequest) request;
    String requestUri = httpRequest.getRequestURI();
    
    // 跳过指定端点的认证逻辑
    if ("/api/v1/test/hola".equals(requestUri)) {
        chain.doFilter(request, response);
        return;
    }
    
    // 原有认证逻辑
    super.doFilter(request, response, chain);
}

方案2:拆分多个SecurityFilterChain

创建两条独立的过滤器链,分别处理不同的请求范围:

  1. 优先级更高的链(Order(1))专门处理无需认证的端点,不添加自定义过滤器:
@Bean
@Order(1)
public SecurityFilterChain publicEndpointFilterChain(HttpSecurity http) throws Exception {
    return http.securityMatcher("/api/v1/test/hola")
            .csrf(Customizer.withDefaults())
            .authorizeHttpRequests(r -> r.anyRequest().permitAll())
            .build();
}
  1. 原有链(Order(2))处理剩余的/api/v1/**端点,添加自定义过滤器:
@Bean
@Order(2)
public SecurityFilterChain generalFilterChain(HttpSecurity http) throws Exception {
    JwtTokenAuthenticationFilter jwtFilter = jwtTokenAuthenticationFilter();
    jwtFilter.setAuthenticationManager(authenticationManager);

    return http.securityMatcher("/api/v1/**")
            .csrf(Customizer.withDefaults())
            .authenticationManager(authenticationManager)
            .authorizeHttpRequests(r -> r.anyRequest().authenticated())
            .addFilterAfter(jwtFilter, UsernamePasswordAuthenticationFilter.class)
            .build();
}

注意:Spring Security会按@Order的优先级匹配第一个符合条件的过滤器链,所以优先级高的链要先匹配特定端点。

方案3:给自定义过滤器设置RequestMatcher

通过RequestMatcher精确控制过滤器的应用范围,排除无需认证的端点:

public JwtTokenAuthenticationFilter jwtTokenAuthenticationFilter() {
    JwtTokenAuthenticationFilter filter = new JwtTokenAuthenticationFilter(APPLICATION_GENERAL_PATH);
    filter.setAuthenticationManager(authenticationManager);
    
    // 设置过滤器仅匹配/api/v1/**,但排除/api/v1/test/hola
    RequestMatcher mainMatcher = new AntPathRequestMatcher("/api/v1/**");
    RequestMatcher excludedMatcher = new NegatedRequestMatcher(new AntPathRequestMatcher("/api/v1/test/hola"));
    filter.setRequestMatcher(new AndRequestMatcher(mainMatcher, excludedMatcher));
    
    return filter;
}

内容的提问来源于stack exchange,提问作者Filip Cacic

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 11:31:15