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

Spring Security集成JWT:如何排除/login端点不被JwtAuthenticationFilter认证?

解决Spring Security中/login路径仍被JwtAuthenticationFilter拦截的问题

看起来你遇到的核心问题是:明明已经配置了忽略/v1/pricing/login路径,但登录请求还是会进入JwtAuthenticationFilter。这背后的原因其实很关键——你的JwtAuthenticationFilter被标记了@Component注解,导致它被Spring自动注册为全局Servlet过滤器,而非仅属于Spring Security的过滤器链。即使你通过WebSecurity.ignoring()排除了该路径,全局过滤器依然会拦截所有请求,包括登录接口。

下面是具体的解决方案:

步骤1:移除JwtAuthenticationFilter上的@Component注解

把@Component从过滤器类上删掉,这样它就不会被自动注册为全局过滤器,只会在你指定的地方生效:

// 移除@Component注解
public class JwtAuthenticationFilter extends OncePerRequestFilter {
    private static final Logger LOGGER = LoggerFactory.getLogger(JwtAuthenticationFilter.class);
    private final JwtTokenProvider jwtTokenProvider;

    // 改用构造函数注入依赖(替代@Autowired)
    public JwtAuthenticationFilter(JwtTokenProvider jwtTokenProvider) {
        this.jwtTokenProvider = jwtTokenProvider;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String jwt = getJwtFromRequest(request);
        if (StringUtils.hasText(jwt) && jwtTokenProvider.validateToken(jwt)) {
            String[] userInfo = jwtTokenProvider.getUserDetailsFromJWT(jwt);
            UserDetails userDetails = new UserPrincipal(Long.parseLong(userInfo[0]), userInfo[1], userInfo[2], null, userInfo[3]);
            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userDetails, null, null);
            authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
            SecurityContextHolder.getContext().setAuthentication(authenticationToken);
        }
        filterChain.doFilter(request, response);
    }

    private String getJwtFromRequest(HttpServletRequest request) {
        String token = request.getHeader("Authorization");
        if (StringUtils.hasText(token)) {
            return token;
        }
        return null;
    }
}

步骤2:在Security配置类中手动创建Filter实例

在你的Spring Security配置类里,通过构造函数注入依赖,并手动实例化JwtAuthenticationFilter,确保它只加入Spring Security的过滤器链:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    private final JwtTokenProvider jwtTokenProvider;
    private final CorsFilter corsFilter;

    // 构造函数注入依赖(更符合Spring最佳实践)
    public SecurityConfig(JwtTokenProvider jwtTokenProvider, CorsFilter corsFilter) {
        this.jwtTokenProvider = jwtTokenProvider;
        this.corsFilter = corsFilter;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeRequests()
                .antMatchers("/v1/pricing/login").permitAll()
                .antMatchers("/v1/pricing/**").authenticated()
                .and()
                .addFilterBefore(corsFilter, UsernamePasswordAuthenticationFilter.class)
                // 使用手动创建的Filter实例
                .addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring()
                .antMatchers("/v1/pricing/login"); // 完全跳过Spring Security过滤器链
    }

    // 手动创建JwtAuthenticationFilter实例
    private JwtAuthenticationFilter jwtAuthenticationFilter() {
        return new JwtAuthenticationFilter(jwtTokenProvider);
    }
}

额外说明:permitAll()和ignoring()的区别

  • permitAll():允许匿名访问,但请求仍会经过Spring Security的完整过滤器链,只是最终判定不需要认证。
  • WebSecurity.ignoring():直接跳过Spring Security的所有过滤器,性能更高,适合登录、静态资源这类完全不需要安全检查的路径。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 09:42:34