我正在尝试设置一堆声明,其中许多包含空值。这些属性必须存在,并且是用户在客户端应用程序中不被拒绝所必需的,即使它们为空。 问题是默认情况下 JJWT 不将 null 值包含到 JWT 中(或者至少看起来是这样)。尽管如此,内部序列化对象确实包含 null 属性。
这就是我添加它们的方式,以及我尝试实现的解决方案,即配置 ObjectMapper 并在 JWT 构建器中使用它。
public String generateTokenFromJwtUserDetails(JwtUserDetails userDetails) {
Date now = new Date();
Date expiryDate = new Date(now.getTime() + jwtExpiration);
Map<String, Object> claims = new HashMap<>();
claims.put("name", userDetails.getName()); // null, will not appear in jwt
claims.put("id", userDetails.getId()); // not null, appears
claims.put("tenant", userDetails.getTenant()); // contains null values that do end up in jwt
// rest of claims...
// here I tried to set serialization inclusion in a custom object mapper, doesn't work
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setSerializationInclusion(JsonInclude.Include.ALWAYS);
// I also tried this, but won't work either
//objectMapper.enable(SerializationFeature.WRITE_NULL_MAP_VALUES);
try{
return Jwts.builder()
.json(new JacksonSerializer<>(objectMapper))
.claims(claims)
.subject(userDetails.getUsername())
.issuedAt(now)
.expiration(expiryDate)
.signWith(getSignInKey())
.issuer(jwtIssuer)
.compact();
}catch(Exception e){ // ...
}
进一步说明:
{
"id": "ibn12u3bio412i",
"tenant": {
"deletedOn": null,
}
}
感谢您的宝贵时间!
JJWT 使用自己的内部逻辑来确定是否序列化或排除声明中的空值。您设置的自定义 ObjectMapper 主要应用于序列化期间的嵌套对象,但不适用于顶级声明映射。
也许这个解决方法会对您有所帮助:
第一: 您需要创建一个自定义 ObjectMapper,就像您已经完成的那样。
objectMapper.setSerializationInclusion(JsonInclude.Include.ALWAYS);
第二: 连载一下:
String serializedClaims = objectMapper.writeValueAsString(claims);
第三: 将其转换回地图。
Map<String, Object> claimsWithNulls = objectMapper.readValue(serializedClaims, new TypeReference<Map<String, Object>>() {});
第四: 现在,您可以为 jwt 提供带有 null 的地图。
Map<String, Object> claimsWithNulls = objectMapper.readValue(serializedClaims, new TypeReference<Map<String, Object>>() {});
试试这个:
try {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setSerializationInclusion(JsonInclude.Include.ALWAYS);
String serializedClaims = objectMapper.writeValueAsString(claims);
Map<String, Object> claimsWithNulls = objectMapper.readValue(serializedClaims, new TypeReference<Map<String, Object>>() {});
return Jwts.builder()
.setClaims(claimsWithNulls)
.setSubject(userDetails.getUsername())
.setIssuedAt(now)
.setExpiration(expiryDate)
.signWith(getSignInKey())
.setIssuer(jwtIssuer)
.compact();
} catch (Exception e) {
throw new RuntimeException("Error generating token", e);
}