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

