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

如何仅对受限HTTP路径应用Spring Security安全过滤器

问题根因

你的过滤器全局生效的核心原因有两个:

  • 你给JwtFilter加了@Component注解,Spring Boot会自动将所有实现了Filter接口且被Spring管理的Bean注册到全局过滤器链,这个链和Spring Security的过滤器链是独立的,无论你在SecurityConfig里怎么配置路径匹配,全局注册的过滤器都会作用于所有请求。
  • 你当前JwtFilter内部逻辑存在bug,token变量未赋值就直接调用jwtUtils.extractUsername(token)和jwtUtils.validateToken(token),即使路径配置正确也会出现校验失败的问题。

解决方案

方案1:移除自动注册,仅在Spring Security链中手动添加

  1. 去掉JwtFilter类上的@Component注解,阻止Spring自动将其注册到全局过滤器链
  2. 调整SecurityConfig中的配置,手动实例化过滤器:
// SecurityConfig中手动创建JwtFilter实例,避免自动注册
private JwtFilter jwtFilter() {
    return new JwtFilter();
}

@Override
protected void configure(final HttpSecurity http) throws Exception {
    http.csrf().disable()
      .antMatcher("/admin/**")
      .authorizeRequests()
      .anyRequest().authenticated()
      .and()
      .addFilterBefore(jwtFilter(), UsernamePasswordAuthenticationFilter.class);
}

此时JwtFilter只会作用于/admin/**开头的路径,其余路径不会触发该过滤器。

方案2:保留@Component注解,禁用全局自动注册

如果你需要保留@Component方便注入依赖,可以新增FilterRegistrationBean配置关闭该过滤器的全局注册:

@Configuration
public class FilterConfig {
    @Bean
    public FilterRegistrationBean<JwtFilter> disableJwtFilterGlobalRegistration(JwtFilter jwtFilter) {
        FilterRegistrationBean<JwtFilter> registration = new FilterRegistrationBean<>(jwtFilter);
        registration.setEnabled(false);
        return registration;
    }
}

配置完成后,JwtFilter仅会在你手动添加的Spring Security过滤器链中生效,不会拦截所有请求。

方案3:过滤器层面控制路径匹配

如果需要更灵活的路径控制,可以重写OncePerRequestFilter的shouldNotFilter方法,直接在过滤器内部判断是否要执行校验逻辑:

@Override
protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException {
    AntPathMatcher pathMatcher = new AntPathMatcher();
    // 以下路径不执行JWT校验
    return pathMatcher.match("/login", request.getServletPath())
            || pathMatcher.match("/register", request.getServletPath())
            || !pathMatcher.match("/admin/**", request.getServletPath());
}

这种方式无需修改注册逻辑,即使过滤器被全局注册也可以正常排除不需要校验的路径。

修复JwtFilter逻辑bug

调整doFilterInternal中的token提取逻辑,避免空指针异常:

@Override
protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
    String authorizationHeader = httpServletRequest.getHeader("Authorization");
    String token = null;
    String userName = null;

    // 正确提取Bearer token
    if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) {
        token = authorizationHeader.substring(7);
        userName = jwtUtils.extractUsername(token);
    }

    // 仅当token不为空时才执行校验
    if (token != null) {
        if (!jwtUtils.validateToken(token)) {
            httpServletResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            return;
        }
        if (userName != null && SecurityContextHolder.getContext().getAuthentication() == null) {
            UsernamePasswordAuthenticationToken authToken =
              new UsernamePasswordAuthenticationToken(userName, null);
            authToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(httpServletRequest));
            SecurityContextHolder.getContext().setAuthentication(authToken);
        }
    }
    filterChain.doFilter(httpServletRequest, httpServletResponse);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 05:57:03