使用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
相关产品推荐
相关产品推荐

