前言

最近自己又在开始闲搞,主要原因还是下山无望(买显卡)。只能晚上下班找点事情做啦~~

环境

版本请根据实际情况参考JJWT官网选择使用,这里只说明一下问题大概思路!

<!-- 增加token生成依赖 -->
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-api</artifactId>
    <version>0.11.4</version>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-impl</artifactId>
    <scope>runtime</scope>
    <version>0.11.4</version>
</dependency>
<!-- 该依赖根据当前项目json解析器选择: 如果选择gson 则引入 jjwt-gson -->
<!-- 需要自定义序列化器, 需注释掉runtime域 -->
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-jackson</artifactId>
    <version>0.11.4</version>
<!--<scope>runtime</scope>-->
</dependency>

问题

最近在重新学习SpringSecurity + JJWT完成整体令牌… 然后就遇到了下面的问题…

简单描述下,问题的根本就是JJWT源码中会寻找当前项目默认使用 ‘JacksonSerializer’ ,源码贴出来看一下,可以看出来如果没有通过构造方法传入一个新的ObjectMapper时,默认使用最基本的对象来进行序列化操作。而默认new出来最基本的序列化对象,是不支持序列化LocalDateTime的。

JJWT中JacksonSerializer源码:

static final ObjectMapper DEFAULT_OBJECT_MAPPER = new ObjectMapper(); private final ObjectMapper objectMapper; @SuppressWarnings("unused") //used via reflection by RuntimeClasspathDeserializerLocator public JacksonSerializer() { this(DEFAULT_OBJECT_MAPPER); } @SuppressWarnings("WeakerAccess") //intended for end-users to use when providing a custom ObjectMapper public JacksonSerializer(ObjectMapper objectMapper) { Assert.notNull(objectMapper, "ObjectMapper cannot be null."); this.objectMapper = objectMapper; } ```

错误结果

java JWT解码包 jwt解析慢_序列化

解决办法

解决问题首先思路肯定是从源码出发,我们从源码中可以看出来,JJWT已经为我们预留了重写默认ObjectMapper的方式了,既然这样最简单的解决方式就是利用 ‘JacksonSerializer’ 中的有参构造来覆写入支持序列化 ‘LocalDateTime’ 的ObjectMapper就可以了.

java JWT解码包 jwt解析慢_spring_02


当然接下来肯定有人要问了,这个构造方法应该在什么时候调用呢?

别着急嘛,正要说到这里~~

JJWT目前提供的计算令牌的方式是通过 ‘Jwts’ 类来进行链式调用完成令牌计算,解析的。
示例如下:

// 获取令牌
Jwts.builder()
    .setClaims(claims)
    .signWith(secretKey(secret))
    .compact();
// 解析令牌
Jwts.parserBuilder()
     .setSigningKey(secretKey(secret))
     .build()
     .parseClaimsJws(token)
     .getBody();

既然知道这个类主要提供给我们用来操作的,那我们就可以在类中查找一下是否提供了序列化的方法。(最好还是先查看文档哦,避免盲目寻找浪费时间,这里我就直接贴出来官方的翻译(仅供参考

自定义 JSON 处理器
如果您不想使用 JJWT 的运行时依赖方式,或者只是想自定义 JSON 序列化和反序列化的工作方式,则可以实现 Serializer 和 Deserializer 接口,并分别在 JwtBuilder 和 JwtParserBuilder 上指定它们的实例。例如:

When creating a JWT(创建JWT时):

//implement meJwts.builder() .serializeToJsonWith(serializer) // ... etc ... ```

When reading a JWT(读取 JWT 时):

getMyDeserializer(); //implement meJwts.parserBuilder() .deserializeJsonWith(deserializer) // ... etc ... ```

w(゚Д゚)w 看完文档是不是豁然开朗,接下来只需要将自定义可以序列化万物的 serializer 交出来就可以了~

// PS. 这是两个分开的方法哦 记住了吗~
Jwts.builder()
     // 使用项目配置的json序列化器
     .serializeToJsonWith(new JacksonSerializer<>(JsonUtil.MAPPER))
     .setClaims(claims)
     .signWith(secretKey(secret))
     .compact();
// ----------------------------------
Jwts.parserBuilder()
     .deserializeJsonWith(new JacksonDeserializer<>(JsonUtil.MAPPER))
     .setSigningKey(secretKey(secret))
     .build()
     .parseClaimsJws(token)
     .getBody();

测试验证结果

java JWT解码包 jwt解析慢_自定义_03


؏؏☝ᖗ乛◡乛ᖘ☝؏؏

验证通过,完结撒花~