当前位置:首页 > 问答 > 正文

Redis集群里头用JWT搞认证,安全又快,还挺实用的那种感觉

(引用来源:根据常见的Redis集群、JWT认证技术实践及Web应用安全架构模式综合阐述)

在现在这种到处都是网站和App的时代,怎么让用户既能快速登录,又能保证安全,是每个开发团队都要头疼的问题,你肯定遇到过,登录一个应用,有时候卡半天,有时候又让你反复登录,烦都烦死了,现在有一种挺流行的做法,就是把Redis集群和JWT这两个东西凑到一块儿用,用下来感觉就是:安全上够用,速度上飞快,而且实际用起来特别顺手,有种“刚刚好”的感觉。

先说说JWT是啥,你可以把它想象成一张演唱会门票,这张票很特别,它自己身上就印着你的座位信息(比如用户ID、权限)、什么时候过期,检票员(就是我们的服务器)拿到这张票,不需要打电话问售票处(数据库)验票,只需要看看票本身的防伪标记(数字签名)对不对,再看看过期了没有,就能直接放你进去,这样一来,服务器就轻松多了,因为它不用每次都去查数据库,这就是所谓的“无状态”,速度自然就快了。

但光有JWT也不行,它有个小麻烦,比如你这张票的有效期是一天,那你这一天内进出场馆都不用再买票,很方便,可万一你想中途退票(用户主动退出登录),或者场馆管理员发现你这张票是偷来的,想把它拉黑,怎么办?票在你自己手里,服务器又没存底,它没法当场宣布这张票失效,这就是JWT的“注销难题”。

这时候,Redis集群就该上场了,Redis是个速度超级快的内存数据库,你可以把它理解为场馆旁边设立的一个超级高效的“小黑板”或者“临时管理处”,我们不再把JWT门票完全“无状态”化,而是给它加一个轻量的状态管理,具体怎么做呢?

当用户成功登录,服务器生成JWT门票的同时,会把这张门票的ID(一个唯一的序列号)和它的“作废状态”记录在Redis集群里,这个记录非常小,基本上就是“门票ID:有效”这么一个键值对,而且我们给它设置一个和JWT门票本身一样的过期时间,这样一来,Redis里就不会堆积太多过期数据,它能自己清理。

当用户拿着JWT门票来访问的时候,检票流程就变成了两步:第一步,和以前一样,先检查门票本身的真伪和有效期(验证JWT签名和过期时间),第二步,快速地去旁边的Redis小黑板上查一下:“请问这张门票ID被拉黑了吗?” Redis的速度是出了名的快,每秒处理几十万次请求跟玩儿一样,所以这个检查动作几乎感觉不到延迟。

这么做,好处立刻就出来了:

第一,解决了注销问题,用户一点“退出登录”,服务器立马在Redis小黑板上把这张门票ID标记为“已失效”,下次即使坏人捡到了这张还没过期的门票,一来检票口,一查小黑板,“此票已作废”,直接拒之门外,同样,管理员可以随时拉黑任何可疑的门票。

第二,保持了高性能,最关键的用户认证逻辑(验证JWT签名)还是很快,因为它是本地计算,新增的Redis查询操作,由于其内存速度和集群的高可用性,对系统性能的影响微乎其微,几乎可以忽略不计,相比起每次都要去慢速的关系型数据库里查询用户信息、权限表,这种方案的速度优势是碾压性的。

第三,特别适合集群环境,现在稍微大点的应用都不是一台服务器了,而是由很多台服务器组成的集群,如果只用JWT,每台服务器都能独立验票,很方便,但想拉黑一张票,就得通知所有服务器,很麻烦,现在有了Redis集群,它充当了一个统一的、高速的“信息中心”,所有服务器都向同一个Redis集群查询票务状态,信息瞬间同步,管理起来特别简单。

第四,感觉上很实用,这种感觉来自于一种平衡,我们没有为了极致的速度而完全放弃安全控制(像纯JWT无状态那样),也没有为了绝对的安全而牺牲掉所有的性能(像每次都要查数据库的Session方式),我们在两者之间找到了一个非常好的平衡点:用JWT承担主要的认证压力保证速度,用Redis做一个轻量的“备忘录”来解决最头疼的注销和安全问题,这种设计不复杂,容易理解和实现,但效果却出奇的好,给人一种“四两拨千斤”的巧妙感。

这种感觉要持续,也得注意一些细节,Redis集群本身要高可用,不能动不动就宕机,否则整个认证就卡壳了,JWT的密钥要保管得像命根子一样,绝对不能泄露,还有,令牌的过期时间要设置得合理,不能太长也不能太短。

把Redis集群和JWT捏在一起搞认证,就像是给快车(JWT)装上了灵敏的刹车和方向盘(Redis的状态管理),它既保留了风驰电掣的速度感,又具备了关键时刻能刹得住的安全保障,对于大多数追求用户体验和基础安全并重的互联网应用来说,这种方案带来的正是一种“踏实又爽快”的实用感觉。

Redis集群里头用JWT搞认证,安全又快,还挺实用的那种感觉