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

使用JwtBuilder生成JWT令牌时提取值出现ClassCastException问题

解决JwtBuilder生成JWT后提取值时的ClassCastException问题

嘿,我来帮你搞定这个JWT解析时的ClassCastException问题!这种报错十有八九是声明的类型在存入和取出时不匹配导致的,结合你给出的令牌创建代码片段,我们来一步步排查解决:

常见原因及对应解决方案

1. 声明存入时的自动类型转换坑

你在构建JWT时传入的businessAccountId、consumerAccountId这类Long类型参数,如果出现null值,部分JJWT版本会自动将其转换为Integer(甚至String)类型存入声明。等你解析时用Long强转,自然就会抛出ClassCastException。

解决办法:存入声明时显式处理null值,确保类型统一:

private JwtBuilder getJwtBuilder(String jti, Long issuedAt, Long expiredAt, Long businessAccountId, Long consumerAccountId, String deviceId) {
    JwtBuilder builder = Jwts.builder();
    builder.setIssuer("SO");
    builder.setSubject(TokenConstant.TOKEN_SUBJECT);
    builder.setId(jti);
    builder.setIssuedAt(new Date(issuedAt));
    builder.setExpiration(new Date(expiredAt));
    
    // 显式处理null,确保存入的是Long类型
    builder.claim("businessAccountId", businessAccountId != null ? businessAccountId : 0L);
    builder.claim("consumerAccountId", consumerAccountId != null ? consumerAccountId : 0L);
    builder.claim("deviceId", deviceId);
    
    return builder;
}

2. 解析时直接强转的不安全操作

很多开发者会直接写(Long) claims.get("businessAccountId"),但如果JWT里的声明实际是Integer或String类型(比如序列化时被自动转换),强转必然报错。

解决办法:先获取Object对象,再做类型判断后安全转换:

// 解析JWT获取Claims
Claims claims = Jwts.parserBuilder()
        .setSigningKey(yourSecretKey)
        .build()
        .parseClaimsJws(tokenString)
        .getBody();

// 安全提取Long类型值
Object businessAccountObj = claims.get("businessAccountId");
Long businessAccountId = null;
if (businessAccountObj instanceof Integer) {
    businessAccountId = ((Integer) businessAccountObj).longValue();
} else if (businessAccountObj instanceof Long) {
    businessAccountId = (Long) businessAccountObj;
} else if (businessAccountObj instanceof String) {
    businessAccountId = Long.parseLong((String) businessAccountObj);
}

3. JJWT版本差异导致的类型处理不一致

不同版本的JJWT对声明类型的序列化逻辑有差异,比如旧版本(0.9.x及以下)会把小范围的Long值自动转成Integer,新版本则会严格保留类型。

解决办法:升级到稳定的最新版本(推荐0.11.5+),并明确引入完整依赖:

<!-- Maven依赖示例 -->
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-api</artifactId>
    <version>0.11.5</version>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-impl</artifactId>
    <version>0.11.5</version>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-jackson</artifactId>
    <version>0.11.5</version>
    <scope>runtime</scope>
</dependency>

4. 进阶方案:用DTO实现类型安全的声明处理

如果自定义声明较多,推荐封装成DTO类,借助Jackson做序列化/反序列化,彻底避免类型转换问题:

// 自定义声明DTO
public class TokenCustomClaims {
    private Long businessAccountId;
    private Long consumerAccountId;
    private String deviceId;
    
    // 省略getter、setter
}

// 存入声明时
TokenCustomClaims customClaims = new TokenCustomClaims();
customClaims.setBusinessAccountId(businessAccountId);
customClaims.setConsumerAccountId(consumerAccountId);
customClaims.setDeviceId(deviceId);

builder.addClaims(new ObjectMapper().convertValue(customClaims, Map.class));

// 解析时
TokenCustomClaims parsedClaims = new ObjectMapper()
        .convertValue(claims, TokenCustomClaims.class);
Long businessAccountId = parsedClaims.getBusinessAccountId();

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 07:46:09