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
相关产品推荐
相关产品推荐

