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

Spring Boot 3中JWT签名异常自定义处理方案咨询

解决Spring Boot 3 + Security 6中JWT SignatureException无法返回统一响应的问题

核心问题分析

你遇到的问题是SignatureException作为RuntimeException,未被过滤器捕获,直接被Spring Security默认异常机制处理,导致无法返回自定义的ApiError响应。另外代码存在逻辑反转:当前if (jwtService.isTokenValid(jwt))分支处理过期,但正常isTokenValid返回true代表令牌有效,返回false才是过期,这会导致逻辑错误。

解决方案步骤

1. 在过滤器中主动捕获SignatureException

修改doFilterInternal方法,将调用isTokenValid的代码包裹在try-catch块中,直接捕获JWT相关异常并调用错误处理方法:

protected void doFilterInternal(
        @NonNull HttpServletRequest request,
        @NonNull HttpServletResponse response,
        @NonNull FilterChain filterChain
) throws ServletException, IOException {
    String jwt = parseJwt(request);

    if (jwt != null) {
        try {
            boolean tokenValid = jwtService.isTokenValid(jwt);
            // 修正逻辑:令牌无效(过期)时返回错误响应
            if (!tokenValid) {
                System.out.println("Token is expired");
                handleAuthorisationDenied(response, "Unauthorised access: Security token expired");
                return;
            }
            // 令牌有效则继续执行过滤器链
            filterChain.doFilter(request, response);
        } catch (io.jsonwebtoken.security.SignatureException e) {
            // 处理签名异常
            handleAuthorisationDenied(response, "Unauthorised access: Invalid JWT signature");
            return;
        } catch (io.jsonwebtoken.ExpiredJwtException e) {
            // 单独处理过期异常
            handleAuthorisationDenied(response, "Unauthorised access: Security token expired");
            return;
        } catch (Exception e) {
            // 兜底处理其他JWT相关异常
            handleAuthorisationDenied(response, "Unauthorised access: Invalid authentication token");
            return;
        }
    } else {
        // 无令牌时继续执行(可根据业务需求调整为直接返回未授权)
        filterChain.doFilter(request, response);
    }
}

2. 调整JwtService的isTokenValid方法

确保isTokenValid只处理过期判断,不要捕获SignatureException,让异常向上抛到过滤器处理:

public boolean isTokenValid(String jwt) {
    Claims claims = Jwts.parser()
            .setSigningKey(yourSecretKey) // 替换为你的签名密钥
            .parseClaimsJws(jwt)
            .getBody();
    
    // 判断令牌是否过期
    return !claims.getExpiration().before(new Date());
}

如果需要单独处理过期异常,可在service中捕获ExpiredJwtException并返回false,让过滤器的!tokenValid分支处理:

public boolean isTokenValid(String jwt) {
    try {
        Claims claims = Jwts.parser()
                .setSigningKey(yourSecretKey)
                .parseClaimsJws(jwt)
                .getBody();
        return !claims.getExpiration().before(new Date());
    } catch (ExpiredJwtException e) {
        // 令牌过期返回false
        return false;
    }
    // 不要捕获SignatureException、MalformedJwtException等,让它们抛到过滤器处理
}

3. 验证异常处理逻辑

测试时携带无效签名的JWT令牌,此时SignatureException会被过滤器捕获,调用handleAuthorisationDenied返回自定义JSON错误响应,与过期令牌的处理逻辑保持一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 10:17:44