You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Postman JWT认证场景空响应体问题及代码求助

解决Postman中JWT认证接口无响应体的问题

我看了你的代码,发现几个关键问题导致Postman里看不到错误响应体,我们一步步来修复:

问题1:空Authorization头时返回200空体

你的JwtFilter里犯了一个低级错误——只有当token解析出用户名时才执行过滤器链,如果没有token或者格式不对,filterChain.doFilter根本不会被调用,请求直接被截断,所以返回200空体。

修复JwtFilter的过滤器链执行逻辑

filterChain.doFilter移到if块外面,确保无论有没有token,请求都会继续走到Spring Security的认证流程:

@Override
protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse
        , FilterChain filterChain) throws ServletException, IOException {
    final String requestHeader = httpServletRequest.getHeader("Authorization");
    String name = null;
    String jwt = null;

    try {
        if (requestHeader != null && requestHeader.startsWith("Bearer ")) {
            jwt = requestHeader.substring(7);
            name = jwtUtil.extractUsername(jwt);
        }

        if (name != null && SecurityContextHolder.getContext().getAuthentication() == null) {
            UserDetails userDetails = userDetailsServiceImp.loadUserByUsername(name);
            if (jwtUtil.validateToken(jwt, userDetails)) {
                UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
                usernamePasswordAuthenticationToken
                        .setDetails(new WebAuthenticationDetailsSource().buildDetails(httpServletRequest));
                SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
            } else {
                throw new BadCredentialsException("Invalid JWT token");
            }
        }
    } catch (ExpiredJwtException | SignatureException | MalformedJwtException e) {
        throw new AuthenticationServiceException("JWT authentication failed: " + e.getMessage(), e);
    }

    // 关键:无论是否有token,都必须执行这行代码
    filterChain.doFilter(httpServletRequest, httpServletResponse);
}

问题2:Token验证逻辑完全反转

你的JwtUtil.validateToken方法里,判断token是否有效的逻辑写反了!isTokenExpired(token)返回true表示token过期,但你却把它作为验证通过的条件,这会导致只有过期的token才会被认为有效,完全搞反了。

修复JwtUtil的validateToken方法

isTokenExpired(token)前面加个非运算符!

public boolean validateToken(String token, UserDetails userDetails) {
    final String username = extractUsername(token);
    // 验证用户名匹配且token未过期
    return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));
}

问题3:sendError无法在Postman中显示响应体

response.sendError()方法在某些情况下不会返回自定义的响应体,Postman无法识别。我们需要手动设置响应的Content-Type为JSON,然后写入结构化的错误信息。

修复JwtAuthenticationEntryPoint的异常处理

@Component
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint, Serializable {
    private static final long serialVersionUID = -7858869558953243875L;

    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException {
        // 设置响应格式为JSON
        response.setContentType("application/json");
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        
        // 写入JSON格式的错误信息
        PrintWriter writer = response.getWriter();
        writer.write("{\"code\": 401, \"message\": \"" + authException.getMessage() + "\"}");
        writer.flush();
        writer.close();
    }
}

问题4:未捕获JWT解析异常

当token格式错误、签名无效或者过期时,extractAllClaims会抛出异常,但你的过滤器没有捕获这些异常,导致直接返回500错误,而不是我们期望的401。我们需要把这些异常转换为Spring Security的AuthenticationException,让异常处理器来处理。

在JwtFilter中捕获JWT相关异常

在doFilterInternal方法里添加try-catch块,捕获JWT的异常并转换:

// 需要导入这些类
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.BadCredentialsException;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.SignatureException;

// 然后在方法里添加try-catch
try {
    // 原有的token解析和验证逻辑
} catch (ExpiredJwtException | SignatureException | MalformedJwtException e) {
    // 转换为Spring Security认证异常,触发entryPoint处理
    throw new AuthenticationServiceException("JWT authentication failed: " + e.getMessage(), e);
}

验证效果

修改完这些代码后,重新启动服务:

  • 当Authorization头为空时,会返回401状态码,响应体是{"code": 401, "message": "Full authentication is required to access this resource"}
  • 当Token不正确(格式错、签名错、过期)时,会返回401状态码,响应体是对应的错误信息,比如{"code": 401, "message": "JWT authentication failed: JWT signature does not match locally computed signature"}

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

火山引擎 最新活动