社区编辑申请
注册/登录
实战!退出登录时如何借助外力使JWT令牌失效?
服务器
JWT最大的一个优势在于它是无状态的,自身包含了认证鉴权所需要的所有信息,服务器端无需对其存储,从而给服务器减少了存储开销。

本文转载自微信公众号「码猿技术专栏」,作者不才陈某。转载本文请联系码猿技术专栏公众号。

今天这篇文章介绍一下如何在修改密码、修改权限、注销等场景下使JWT失效。

文章的目录如下:

解决方案

JWT最大的一个优势在于它是无状态的,自身包含了认证鉴权所需要的所有信息,服务器端无需对其存储,从而给服务器减少了存储开销。

但是无状态引出的问题也是可想而知的,它无法作废未过期的JWT。举例说明注销场景下,就传统的cookie/session认证机制,只需要把存在服务器端的session删掉就OK了。

但是JWT呢,它是不存在服务器端的啊,好的那我删存在客户端的JWT行了吧。额,社会本就复杂别再欺骗自己了好么,被你在客户端删掉的JWT还是可以通过服务器端认证的。

使用JWT要非常明确的一点:JWT失效的唯一途径就是等待时间过期。

但是可以借助外力保存JWT的状态,这时就有人问了:你这不是打脸吗?用JWT就因为它的无状态性,这时候又要保存它的状态?

其实不然,这不被逼上梁山了吗?不使用外力保存JWT的状态,你说如何实现注销失效?

常用的方案有两种,白名单和黑名单方式。

1、白名单

白名单的逻辑很简单:认证通过时,将JWT存入redis中,注销时,将JWT从redis中移出。这种方式和cookie/session的方式大同小异。

2、黑名单

黑名单的逻辑也非常简单:注销时,将JWT放入redis中,并且设置过期时间为JWT的过期时间;请求资源时判断该JWT是否在redis中,如果存在则拒绝访问。

白名单和黑名单这两种方案都比较好实现,但是黑名单带给服务器的压力远远小于白名单,毕竟注销不是经常性操作。

黑名单方式实现

下面以黑名单的方式介绍一下如何在网关层面实现JWT的注销失效。

究竟向Redis中存储什么?

如果直接存储JWT令牌可行吗?当然可行,不过JWT令牌可是很长的哦,这样对内存的要求也是挺高的。

熟悉JWT令牌的都知道,JWT令牌中有一个jti字段,这个字段可以说是JWT令牌的唯一ID了,如下:

因此可以将这个jti字段存入redis中,作为唯一令牌标识,这样一来是不是节省了很多的内存?

如何实现呢? 分为两步:

  • 网关层的全局过滤器中需要判断黑名单是否存在当前JWT
  • 注销接口中将JWT的jti字段作为key存放到redis中,且设置了JWT的过期时间

1、网关层解析JWT的jti、过期时间放入请求头中

在网关的全局过滤器GlobalAuthenticationFilter中直接从令牌中解析出jti和过期时间。

这里的逻辑分为如下步骤:

解析JWT令牌的jti和过期时间

根据jti从redis中查询是否存在黑名单中,如果存在则直接拦截,否则放行

将解析的jti和过期时间封装到JSON中,传递给下游微服务

关键代码如下:

2、下游微服务的过滤器修改

还记得上篇文章:实战干货!Spring Cloud Gateway 整合 OAuth2.0 实现分布式统一认证授权!中微服务的过滤器AuthenticationFilter吗?

AuthenticationFilter这个过滤器用来解密网关层传递的JSON数据,并将其封装到Request中,这样在业务方法中便可以随时获取到想要的用户信息。

这里我是把JWT相关的信息同时封装到了Request中,实体类为JwtInformation,如下:

LoginVal继承了JwtInformation,如下:

此时AuthenticationFilter这个过滤器修改起来就很简单了,只需要将jti和过期时间封装到LoginVal中即可,关键代码如下:

逻辑很简单,上图都有标注。

3、注销接口实现

之前文章中并没有提供注销接口,因为无状态的JWT根本不需要退出登录,傻等着过期呗。

当然为了实现注销登录,借助了Redis,那么注销接口必不可少了。

逻辑很简单,直接将退出登录的JWT令牌的jti设置到Redis中,过期时间设置为JWT过期时间即可。代码如下:

OK了,至此已经实现了JWT注销登录的功能.......

涉及到的三个模块的改动,分别如下:

名称 功能
oauth2-cloud-auth-server OAuth2.0认证授权服
oauth2-cloud-gateway 网关服务
oauth2-cloud-auth-common 公共模块

总结

思想很简单,JWT既然是无状态的,只能借助Redis记录它的状态,这样才能达到使其失效的目的。

测试

业务基本完成了,下面走一个流程测试一下,如下:

1、登录,申请令牌

2、拿着令牌访问接口

该令牌并没有注销,因此可以正常访问,如下:

3、调用接口注销登录

请求如下:

4、拿着注销的令牌访问接口

由于令牌已经注销了,因此肯定访问不通接口,返回如下:

 

责任编辑:武晓燕 来源: 码猿技术专栏
相关推荐

2022-03-23 12:45:12

JWT登录认证

2022-01-18 08:12:34

2022-05-09 16:33:03

EDR终端安全

2022-04-25 11:26:16

开发SpringBoot

2022-04-13 20:53:15

Spring事务管理

2022-02-28 08:55:31

数据库MySQL索引

2022-04-19 12:58:20

网络攻击黑客

2022-03-08 00:07:51

缓存雪崩数据库

2022-01-09 18:32:03

2021-10-22 09:00:59

2022-04-21 09:00:00

API安全密钥

2022-05-17 10:45:55

2022-05-17 07:35:13

2022-05-11 08:45:49

VaultGitlab加密

2022-04-06 07:50:57

2019-07-31 07:57:14

零信任网络安全数据安全

2021-10-14 06:51:54

2022-05-16 18:42:43

微隔离云原生

2022-04-16 21:32:03

GitHub攻击OAuth

2022-04-18 11:24:39

网络攻击GitHub数据泄露

同话题下的热门内容

浅谈微服务的发展以及可观测性新型数据中心的建设及发展启示无服务器计算或已成为云原生的下一个演进保护微服务架构安全的三个优秀实践字节跳动自研高性能微服务框架 Kitex 的演进之旅携程 SOA 的 Service Mesh 架构落地数据中心如何进行定制化配电设计?安谋科技结束纷争,看新管理团队如何开启新阶段?

编辑推荐

什么是中间件,常见中间件服务器有哪些?如何快速搭建一个阿里云服务器Windows和Ubuntu系统如何远程连接Linux服务器Python与PHP、Java等4大流行语言过招,谁更胜一筹?解决Nginx服务返回500状态码问题
我收藏的内容
点赞
收藏

51CTO技术栈公众号