spring cloud实战与思考(四) JWT之Token主动失效

时间:2021-04-11 03:43:31

需求:

JWT泄露、密码重置等场景下,需要将未过期但是已经不安全的JWT主动失效。

本文不再复述JWT的基础知识,不了解的小伙伴可以自行Google一下。这里主要是针对以上需求聊一聊解决方案。如果服务端发给客户端的JWT还在有效期内,但是变得不安全,服务端需要及时将这些JWT标识出来并作废掉。相较于session机制,服务端对JWT的控制要弱很多。JWT一旦签发,就脱离了服务端的掌控。通常情况下,服务端只能通过设置JWT的过期时间“exp”声明,使得JWT在过期后被动失效。

正所谓鱼与熊掌不可兼得。在我们享受JWT便利性的同时,也要设计复杂点的机制来弥补服务器对JWT控制能力弱的缺点。网上有人建议服务器将签发的JWT都存一份到分布式缓存中,这样JWT就能被跟踪和标识。这种方式虽然解决了问题,但是每个JWT都保存起来,每次校验都做查询的方式同分布式session几乎无分别。这相当于放弃了JWT占用服务器空间小、有效性校验速度快的优点。在没有跨域资源访问的需求场景下,分布式session的方案反而更有优势,至少可以在session中保存敏感信息,而不用担心在客户端被泄露。

下面讲一下我在当前项目中使用的JWT控制方案:

  1. 每个JWT必须设置过期时间,并且该时间不要设置的过长。

  2. 在用户登陆表中,为每个用户分配一个“token_group_id”字段。该字段保存一个随机字符串。

    spring cloud实战与思考(四) JWT之Token主动失效

  3. 在JWT的payload中增加“groupId”声明。签发JWT的时候,将用户对应的“token_group_id”字符串写入该声明。

    {

      "exp": 1525256018000,

      "groupId": "jeJ4IVpR17z68Q0cTr53gQ25e588P653"

    }

  4. 在服务端的分布式缓存上保存一个“groupId”黑名单列表。如果用户的JWT泄露或者重置密码等需要作废已经签发给用户的JWT时,为该用户生成一个新的“token_group_id”存入用户登陆表。将原有的“token_group_id”加入黑名单。

  5. “token_group_id”在黑名单中的保存时间是JWT的过期时间。过期后“token_group_id”自动从黑名单中删除。

  6. 所有需要做JWT有效性校验的服务器启动时访问分布式缓存将黑名单下载到本地内存。并且订阅分布式缓存的消息推送功能,在黑名单发生增删的时候,接收推送消息同步修改内存中的黑名单列表。

  7. 服务器做JWT校验的时候,除了校验过期时间,还要查询内存中的黑名单列表。若JWT的“groupId”在黑名单中,则判定该JWT为失效。

讨论:

  1. 你这个方案也用到了分布式缓存,也要在缓存中保存数据。这和分布式session或者保存所有的JWT的方案性质不是一样的吗?

    形式上虽然相同,但是保存数据的数量级差别很大。其它两种方案需要保存当前活动用户的全集,而本方案只保存不安全的JWT。相信通常情况下出现token泄露和密码重置的频率是比较低的。需要撤销的JWT占整个活动用户的百分比很小。

    此外JWT只在黑名单中保存一个过期周期,此后就会被删除,进一步控制了黑名单的增长。这样黑名单就可以装载到服务器的内存中,协助完成JWT的本地校验。而无需每次校验时要访问远端服务。

  2. 为什么多此一举的新增一个“groupId”,直接将需要作废的JWT放到黑名单中不就行了吗?

    1) JWT本身比较长,使用较短的“groupId”可以加快黑名单的查询速度。

    2) 若系统不限制用户同一时间能申请的JWT数量。那么可能遇到用户在短时间内恶意请求大量Token的情况。这些Token都放到黑名单中会导致黑名单数量迅速膨胀。使用“groupId”则可以避免这种不可控情况。

  3. 你这个方案又要分布式缓存,又要做黑名单的实时同步。整个方案实施的复杂性似乎超过了分布式session,用它代替分布式session会不会得不偿失?

    1)在一个稍具规模的分布式系统中,分布式缓存、系统总线都是必备的组件。利用这些现有组件可以设计多种方案做数据同步。所以方案看似复杂,实现起来还是不难的。

    2)每个系统侧重的性能指标各有不同。本方案的JWT校验的计算和查询都是在本地内存中完成,不需要依赖远端服务。能够缩短请求的响应时间。对于强调低延迟响应的系统还是比较合适的。

spring cloud实战与思考(四) JWT之Token主动失效的更多相关文章

  1. spring cloud实战与思考(二) 微服务之间通过fiegn上传一组文件(上)

    需求场景: 微服务之间调用接口一次性上传多个文件. 上传文件的同时附带其他参数. 多个文件能有效的区分开,以便进行不同处理. Spring cloud的微服务之间接口调用使用Feign.原装的Feig ...

  2. spring cloud实战与思考(一) spring config全局配置方案设计

    “spring cloud”的配置中心工具“spring cloud config”提供了分布式系统配置文件集中管理解决方案.该工具功能强大,实现也很简单.网上可以搜索到很多开发教程和用例.本文并不是 ...

  3. spring cloud实战与思考(五) JWT之携带敏感信息

    需求: 需要将一些敏感信息保存在JWT中,以便提高业务处理效率. 众所周知JWT协议RFC7519使用Base64Url对Header和Payload的Json字符串进行编解码.A JWT is re ...

  4. spring cloud实战与思考(三) 微服务之间通过fiegn上传一组文件(下)

    需求场景: 用户调用微服务1的接口上传一组图片和对应的描述信息.微服务1处理后,再将这组图片上传给微服务2进行处理.各个微服务能区分开不同的图片进行不同处理. 上一篇博客已经讨论了在微服务之间传递一组 ...

  5. [Spring Cloud实战 | 第六篇:Spring Cloud Gateway+Spring Security OAuth2+JWT实现微服务统一认证授权

    一. 前言 本篇实战案例基于 youlai-mall 项目.项目使用的是当前主流和最新版本的技术和解决方案,自己不会太多华丽的言辞去描述,只希望能勾起大家对编程的一点喜欢.所以有兴趣的朋友可以进入 g ...

  6. Spring Cloud实战 | 最终篇:Spring Cloud Gateway+Spring Security OAuth2集成统一认证授权平台下实现注销使JWT失效方案

    一. 前言 在上一篇文章介绍 youlai-mall 项目中,通过整合Spring Cloud Gateway.Spring Security OAuth2.JWT等技术实现了微服务下统一认证授权平台 ...

  7. Spring Cloud实战 | 最八篇:Spring Cloud +Spring Security OAuth2+ Axios前后端分离模式下无感刷新实现JWT续期

    一. 前言 记得上一篇Spring Cloud的文章关于如何使JWT失效进行了理论结合代码实践的说明,想当然的以为那篇会是基于Spring Cloud统一认证架构系列的最终篇.但关于JWT另外还有一个 ...

  8. Spring Cloud实战之初级入门(四)— 利用Hystrix实现服务熔断与服务监控

    目录 1.环境介绍 2.服务监控 2.1 加入依赖 2.2 修改配置文件 2.3 修改启动文件 2.4 监控服务 2.5 小结 3. 利用hystrix实现消费服务熔断 3.1 加入服务熔断 3.2 ...

  9. Spring Cloud实战 | 第九篇:Spring Cloud整合Spring Security OAuth2认证服务器统一认证自定义异常处理

    本文完整代码下载点击 一. 前言 相信了解过我或者看过我之前的系列文章应该多少知道点我写这些文章包括创建 有来商城youlai-mall 这个项目的目的,想给那些真的想提升自己或者迷茫的人(包括自己- ...

随机推荐

  1. UOJ30——【CF Round #278】Tourists

    1.感谢taorunz老师 2.题目大意:就是给个带权无向图,然后有两种操作, 1是修改某个点的权值 2是询问,询问一个值,就是u到v之间经过点权的最小值(不可以经过重复的点) 操作数,点数,边数都不 ...

  2. Android中Service深入学习

    概述 1.当用户在与当前应用程序不同的应用程序时,Service可以继续在后台运行. 2.Service可以让其他组件绑定,以便和它交互并进行进程间通信. 3.Service默认运行在创建它的应用程序 ...

  3. 使用isInEditMode解决可视化编辑器无法识别自定义控件的问题

    如果在自定义控件的构造函数或者其他绘制相关地方使用系统依赖的代码, 会导致可视化编辑器无法报错并提示:Use View.isInEditMode() in your custom views to s ...

  4. linux-0.11 内核源码学习笔记一(嵌入式汇编语法及使用)

    linux内核源码虽然是用C写的,不过其中有很多用嵌入式汇编直接操作底层硬件的“宏函数”,要想顺利的理解内核理论和具体实现逻辑,学会看嵌入式汇编是必修课,下面内容是学习过程中的笔记:当做回顾时的参考. ...

  5. Luogu P3379 【模板】最近公共祖先(LCA)

    qwq 预处理出从$x$节点向上跳2i个节点的序号$p[x][i]$及节点深度$dpth[x]$, 寻找$lca$时,从$Max$(可能的最大深度)到0枚举$i$, 首先把较深的一个节点向上跳至深度相 ...

  6. android--------Android Studio常见问题以及解决方式

    gradle build的时候出现的问题: Error:Execution failed for task ':app:packageDebug'. Duplicate files copied in ...

  7. 我的CSDN博客&Github地址

    我的 CSDN 博客地址: https://blog.csdn.net/qq_40147863 Github 地址: https://github.com/xpwi

  8. HDU 1271 整数对(思路题)

    假设删除第k位,把整数A表示成如下形式: A = a * 10^(k+1) + b * 10 ^k + c; 则: B = a * 10^k + c; N = A + B = (11*a+b)*10^ ...

  9. 初涉Quartz

    1.首先需要导入包,必须导入的包如下:      quartz-1.8.5.jar  commons-logging.jar  spring-core-3.0.5.RELEASE.jar  sprin ...

  10. 【Python之os模块】使用

    目录 1. os.path 2. os.work   主要介绍在平时遇到的os模块的使用方法: 1. os.path 1.1 os.path.sep # 系统路径分隔符 # ============= ...