xkcoding/spring-boot-demo · warning · SecurityException

5002

5002

Error message

token 已过期,请重新登录!

What it means

Thrown by JwtUtil.parseJWT when the JWT is considered expired. Two distinct paths produce this: (1) the Redis key holding the JWT (REDIS_JWT_KEY_PREFIX + username) has expired or been deleted (getExpire returns null or <= 0), or (2) the jjwt library's parseClaimsJws throws ExpiredJwtException because the token's own exp claim has passed. Status.TOKEN_EXPIRED (code 5002) wraps the error. The Redis check is a secondary expiry mechanism layered on top of the JWT's built-in expiration.

Source

Thrown at demo-rbac-security/src/main/java/com/xkcoding/rbac/security/util/JwtUtil.java:98

    }

    /**
     * 解析JWT
     *
     * @param jwt JWT
     * @return {@link Claims}
     */
    public Claims parseJWT(String jwt) {
        try {
            Claims claims = Jwts.parser().setSigningKey(jwtConfig.getKey()).parseClaimsJws(jwt).getBody();

            String username = claims.getSubject();
            String redisKey = Consts.REDIS_JWT_KEY_PREFIX + username;

            // 校验redis中的JWT是否存在
            Long expire = stringRedisTemplate.getExpire(redisKey, TimeUnit.MILLISECONDS);
            if (Objects.isNull(expire) || expire <= 0) {
                throw new SecurityException(Status.TOKEN_EXPIRED);
            }

            // 校验redis中的JWT是否与当前的一致,不一致则代表用户已注销/用户在不同设备登录,均代表JWT已过期
            String redisToken = stringRedisTemplate.opsForValue().get(redisKey);
            if (!StrUtil.equals(jwt, redisToken)) {
                throw new SecurityException(Status.TOKEN_OUT_OF_CTRL);
            }
            return claims;
        } catch (ExpiredJwtException e) {
            log.error("Token 已过期");
            throw new SecurityException(Status.TOKEN_EXPIRED);
        } catch (UnsupportedJwtException e) {
            log.error("不支持的 Token");
            throw new SecurityException(Status.TOKEN_PARSE_ERROR);
        } catch (MalformedJwtException e) {
            log.error("Token 无效");
            throw new SecurityException(Status.TOKEN_PARSE_ERROR);
        } catch (SignatureException e) {

View on GitHub (pinned to 87a142f960)

Solutions

  1. On the client, catch the 5002 response and redirect to the login page to obtain a fresh JWT.
  2. Verify Redis connectivity — if Redis is unreachable, all tokens appear expired.
  3. Check jwtConfig.ttl and jwtConfig.remember values in application.yml are appropriate for the use case.
  4. Ensure the Redis key prefix (Consts.REDIS_JWT_KEY_PREFIX) is consistent across create and parse operations.
Defensive patterns

Strategy: try-catch

Validate before calling

// Client-side: check JWT expiry before making authenticated requests
// Decode the exp claim (no signature verification needed for client-side check)
try {
    Claims claims = Jwts.parser().parseClaimsJwt(jwt.split("\\.")[0] + "." + jwt.split("\\.")[1] + ".").getBody();
    if (claims.getExpiration().before(new Date())) {
        // Token expired — refresh or redirect to login
        redirectToLogin();
        return;
    }
} catch (Exception e) {
    redirectToLogin();
}

Try / catch

// Client-side: intercept 5002 token-expired responses
try {
    apiClient.someProtectedResource();
} catch (SecurityException e) {
    if (e.getStatus().getCode() == 5002) {
        // Token expired — redirect to login for a new token
        redirectToLogin();
    }
}

Prevention

When it happens

Trigger: Any authenticated request whose JWT has exceeded its TTL (jwtConfig.ttl or jwtConfig.remember for 'remember me'), or whose Redis backing key has been removed (e.g., by a prior logout). Also fires if the Redis server is down and getExpire returns null.

Common situations: Normal session timeout after the configured TTL; user logged out from another device (Redis key deleted); Redis connection failure causing getExpire to return null; clock skew between token issuance and validation servers; jwtConfig.ttl set very short.

Related errors


AI-assisted analysis of xkcoding/spring-boot-demo@87a142f960 (2026-08-14). Data as JSON: /api/errors/1a214874a7f1b606. Report an issue: GitHub.