[JWT]Auth0的JWT时间序列化问题

    技术2023-05-21  73

    在SpringBoot项目上构建JWT访问token和刷新token时,遇到一个Date类型的问题,由于序列化JWT token时只支持秒,将毫秒级自然丢弃。

    <dependency> <groupId>com.auth0</groupId> <artifactId>java-jwt</artifactId> <version>3.10.3</version> </dependency>

    如果有基于签发时间戳(iat,IssuedAt)的应用,需要特别小心,这是一个坑,比如作为验证。

    解析分发的token,包括exp,nbf,iat:

    { ... "exp": 1594351823, "iat": 1593747023, ... }

    发现都是秒级而非毫秒级的,一般代码中,我们会使用毫秒timestamp:

    //签发时间 final Date issusedAtTime = new Date(); jwtBuilder.withIssuedAt(issusedAtTime); long timestamp = issusedAtTime.getTime();

    经过读JWT源码分析,序列化主要是PayloadSerializer,通过方法dateToSeconds明确了JWT中的日期全部按秒序列化

    public class PayloadSerializer extends StdSerializer<ClaimsHolder> { .... private long dateToSeconds(Date date) { return date.getTime() / 1000L; } }

    顺便研究了下解析类PayloadDeserializer,通过方法getDateFromSeconds将秒级的日期,转换为毫秒然后构造Date对象:

    class PayloadDeserializer extends StdDeserializer<Payload> { .... public Payload deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { Map<String, JsonNode> tree = (Map)p.getCodec().readValue(p, new TypeReference<Map<String, JsonNode>>() { }); if (tree == null) { throw new JWTDecodeException("Parsing the Payload's JSON resulted on a Null map"); } else { String issuer = this.getString(tree, "iss"); String subject = this.getString(tree, "sub"); List<String> audience = this.getStringOrArray(tree, "aud"); Date expiresAt = this.getDateFromSeconds(tree, "exp"); Date notBefore = this.getDateFromSeconds(tree, "nbf"); Date issuedAt = this.getDateFromSeconds(tree, "iat"); String jwtId = this.getString(tree, "jti"); return new PayloadImpl(issuer, subject, audience, expiresAt, notBefore, issuedAt, jwtId, tree, this.objectReader); } } .... Date getDateFromSeconds(Map<String, JsonNode> tree, String claimName) { JsonNode node = (JsonNode)tree.get(claimName); if (node != null && !node.isNull()) { if (!node.canConvertToLong()) { throw new JWTDecodeException(String.format("The claim '%s' contained a non-numeric date value.", claimName)); } else { long ms = node.asLong() * 1000L; return new Date(ms); } } else { return null; } } .... }

     

    至此,破案成功!

     

     

     

    Processed: 0.010, SQL: 9