前言
最近自己又在开始闲搞,主要原因还是下山无望(买显卡)。只能晚上下班找点事情做啦~~
环境
版本请根据实际情况参考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; } ```
错误结果
解决办法
解决问题首先思路肯定是从源码出发,我们从源码中可以看出来,JJWT已经为我们预留了重写默认ObjectMapper的方式了,既然这样最简单的解决方式就是利用 ‘JacksonSerializer’ 中的有参构造来覆写入支持序列化 ‘LocalDateTime’ 的ObjectMapper就可以了.
当然接下来肯定有人要问了,这个构造方法应该在什么时候调用呢?
别着急嘛,正要说到这里~~
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();
测试验证结果
؏؏☝ᖗ乛◡乛ᖘ☝؏؏
验证通过,完结撒花~