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

Spring OncePerRequestFilter导致登录POST请求无法获取JWT令牌

问题分析与解决方案

Hey there! I see exactly what's causing your issue here. Let's break it down:

The Root Problem

Your JwtAuthenticationFilter is stopping the request from proceeding through the filter chain only when there's no valid JWT token. Look at your doFilterInternal method: you only call filterChain.doFilter(request,response) inside the if (StringUtils.hasText(jwt) && jwtProvider.validateToken(jwt)) block.

That means when you send a login request to /api/auth/** (which doesn't have a JWT yet), the filter skips that block and never passes the request along to the rest of the chain—so your login controller never even gets the request, hence no token is returned.

Even though you've configured antMatchers("/api/auth/**").permitAll() in your security config, the addFilterBefore runs before Spring Security's authorization checks. So the filter is blocking the request before it ever gets to the point where Spring Security would allow it through.

The Fix

You need to make sure the filter chain always proceeds, regardless of whether a valid JWT exists. Move the filterChain.doFilter(request,response) call outside the if block. Here's the corrected JwtAuthenticationFilter:

public class JwtAuthenticationFilter extends OncePerRequestFilter {
    @Autowired
    private JwtProvider jwtProvider;
    @Autowired
    private UserDetailsService userDetailsService;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String jwt = getJwtFromRequest(request);
        if (StringUtils.hasText(jwt) && jwtProvider.validateToken(jwt)) {
            String username = jwtProvider.getUsernameFromJwt(jwt);
            UserDetails userDetails = userDetailsService.loadUserByUsername(username);
            UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
            authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
            SecurityContextHolder.getContext().setAuthentication(authentication);
        }
        // Always proceed with the filter chain, even if no JWT was found/validated
        filterChain.doFilter(request, response);
    }

    private String getJwtFromRequest(HttpServletRequest httpServletRequest) {
        String bearerToken = httpServletRequest.getHeader("Authorization");
        if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
            return bearerToken.substring(7);
        }
        return bearerToken;
    }
}

Why This Works

  • When a login request comes in (no JWT), the filter skips the JWT validation logic, then immediately passes the request to the next filter in the chain. Eventually, it reaches your login controller, which generates and returns the JWT.
  • For authenticated requests with a valid JWT, the filter still sets the authentication in the security context as before, then lets the request proceed to the protected endpoint.

Quick Verification

After updating the filter, fire up your app and test the login request in Postman again—it should return the JWT token as expected. Then you can use that token in subsequent requests to access protected endpoints, and the filter will correctly authenticate those requests.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 13:02:29