面试官问:“你们项目的登录认证怎么做的?”
你回答:“登录成功后返回一个 Token,Redis 里保存登录信息,后面的请求带上 Token,再去校验。”
对方接着问:
“JWT 不就是为了无状态吗?你又放进 Redis,那用 JWT 的意义是什么?”
这句话听着挺有压迫感,但先别急着认错。
因为这里至少有两件事没说清楚:你用的 Token,是不是 JWT?项目有没有要求用户退出、封禁以后,旧 Token 马上不能再用?
需求都没对齐,直接讨论 Redis 该不该用,很容易聊成两个人各背各的八股文。
咱们把这道题拆开说。
先别把 Token 和 JWT 当成一回事
Token 是令牌的统称,JWT 只是其中一种格式。
后端完全可以生成一个足够长、不可预测的随机字符串,把它作为登录凭证交给客户端。用户身份、登录时间、设备信息,则保存在 Redis 对应的会话记录里。
后续请求带着这个字符串过来,服务端查询会话,判断这次登录是否还有效。
这套方案不需要 JWT,也能工作。
JWT 的区别在于,它可以自己携带一些信息,比如用户标识、签发方、接收方和过期时间。使用常见的签名型 JWT 时,服务端可以通过验证签名和相关声明,判断是否接受这张令牌,不必为了取得这些信息,逐个查询会话记录。
不过,有个细节别答错:
常见三段式签名 JWT 的 Payload 只是编码,不是加密。
能防止别人悄悄改内容,不代表别人看不到内容。密码、密钥这类东西,不要往里面放。JWT 也有加密形式,但不能把“用了 JWT”直接理解成“内容已经保密”。
所以,面试时最好先交代清楚:
“我们使用的是随机 Token 加 Redis 会话。”
或者:
“我们使用的是 JWT,同时用 Redis 管理会话有效性。”
这两个回答,后面的讨论方向并不一样。
JWT 能验签,但不知道你刚刚把用户踢了
假设一个后台系统在上午 10 点签发了 JWT,过期时间是 10 点 15 分。
10 点 01 分,管理员发现账号异常,把这个用户踢下线。
问题来了:用户手里的那张 JWT,会自己发生变化吗?
不会。
它的签名还是原来的签名,过期时间也还是 10 点 15 分。如果业务接口只检查 JWT 自身,没有查询任何会话、封禁或吊销状态,那么这张令牌仍可能继续通过验证。
前端删除 Token,也解决不了所有问题。
正常客户端确实不会继续发送它,但已经复制出去的那一份,不会因为浏览器清了一次缓存就消失。
改密码也是同样的道理。修改密码,不会自动改变已经签发的 JWT。 要让旧凭证失效,需要认证方案额外处理。
这时再看 Redis,就知道它不是为了凑一个技术栈。
它可以让服务端回答另一个问题:
这张令牌虽然没被篡改、也没过期,但我们现在还认不认它?
项目能接受旧令牌在一小段时间内继续有效,可以考虑短有效期的方案。项目要求退出、封禁后尽快阻止后续访问,就得设计相应的状态检查。
不能一边要求随时踢人,一边又要求所有服务永远只看令牌本身。

Redis 里到底存什么?不一定是整串 JWT
说“Token 放在 Redis”,其实还不够具体。
Redis 存的是全部有效会话,还是已经被撤销的令牌?这两种做法,校验逻辑正好不同。
保存有效会话
一种做法是:JWT 里带上会话编号,Redis 保存这个会话对应的用户、设备和有效状态。
请求进来以后,先完成 JWT 校验,再查对应会话,并确认会话与令牌中的用户匹配。
校验 JWT
↓
查询并核对会话
↓
确认会话仍然有效
↓
继续做接口权限校验
退出登录时,删除或禁用对应会话。只要后续请求必须通过这一步检查,旧 JWT 就不能仅凭自己的签名继续通行。
需要注意的是,这里说的是后续校验不再通过,不是自动撤销已经执行到一半的请求。
多设备登录也要想清楚。用户在手机和电脑上各登录一次,最好有各自的会话编号。否则,本来只想退出手机,结果电脑也一起掉了。
保存已吊销令牌
另一种做法是使用黑名单。
正常签发的 JWT 不逐个登记。需要提前撤销某张令牌时,把它的唯一标识 jti 加进黑名单;有多个签发方时,还要结合可信的签发方标识,避免混淆。
后续请求除了正常的 JWT 校验,还需要检查是否命中黑名单。
这里有两个容易漏掉的地方。
第一,黑名单不等于不查 Redis。 如果每次请求都要实时检查吊销状态,查询开销照样存在。
第二,黑名单不能比旧 JWT 更早失效。 吊销记录至少要保留到这张令牌不再可能被接受,包括校验时允许的时钟偏差。否则,记录先没了,JWT 却还有效,旧令牌就可能重新通过检查。
另外,吊销一张 JWT,不等于封禁了用户的所有设备。要做全端下线,还需要管理这个用户的全部会话,或者增加账号级别的有效状态检查。
所以,“Redis 里存一下”不是完整设计。你得说明白:存哪一类状态,谁来检查,删掉以后影响哪些请求。

既然每次都查 Redis,为什么还要 JWT?
面试官这句追问,其实有价值。
如果 JWT 里只放一个编号,服务端每次都拿这个编号去 Redis 查完整用户信息,而且所有请求都依赖这次查询,那么确实应该考虑:
直接用随机 Token 加 Redis 会话,是不是更简单?
别为了证明之前的选择正确,硬说 JWT 必不可少。
如果项目还需要统一的令牌格式、带签名的声明传递,或者多个服务按约定验证这些声明,那么 JWT 可能仍有作用。但需要说出实际用途,而不是只回答“微服务一般都这么做”。
反过来,如果它只是把一个随机编号包装得更长,又没有带来额外价值,那就没必要坚持。
JWT 加 Redis 可以是合理方案,但“用了两样技术”不等于比“用一样技术”更高级。
还有一点要承认:只要请求有效性依赖 Redis 中的会话或吊销记录,这套认证方案就不是完全无状态了。
承认有状态,不丢人。明明在查状态,却一直强调自己“纯无状态”,才会把后面的回答绕乱。
真正难接的追问:Redis 挂了怎么办?
前面说得再顺,对方问一句“Redis 超时了呢”,就能看出方案有没有考虑完整。
这里一定要区分:
查到了,确认没有记录。
和:
没查成功,不知道有没有记录。
对于有效会话方案,记录不存在通常意味着会话无效;对于黑名单方案,查询成功但没有记录,才表示没有命中这份黑名单。
网络超时,不能直接当成“黑名单里没有”。
如果系统必须靠 Redis 判断当前登录态,那么 Redis 不可用时,就不能为了让接口继续返回成功,临时跳过这一步。对于需要认证的受保护接口,我会拒绝本次处理,并按故障情况返回服务暂不可用等明确结果。
这意味着可用性会受影响,所以才需要提前处理连接超时、容量、故障切换和告警,而不是上线以后用一个 catch 把异常吞掉。
本地缓存也不是没有代价。
把“会话有效”缓存几十秒,可以减少查询,但用户被踢以后,某些实例就可能继续接受旧状态。业务要求多快生效,缓存策略就得跟着调整。
黑名单还要注意内存淘汰。如果它是判断吊销状态的唯一依据,记录被提前淘汰,就可能让仍未过期的旧令牌重新通过校验。
这类数据关系到访问权限,不能按“缓存丢了就丢了”的思路处理。

访问令牌和刷新令牌,也别混着说
还有一种回答很常见:
“访问令牌用 JWT,刷新令牌放 Redis,不就解决了吗?”
它能解决一部分问题,但不是所有问题。
访问令牌用于访问业务接口;刷新令牌用于换取新的访问令牌。把刷新过程放到服务端控制,可以在续发令牌时检查会话是否仍然有效。
但假设业务接口仍然只做 JWT 本地校验:
删除刷新令牌,通常只是阻止它继续换取新令牌,并不会自动通知所有接口,让已经发出的访问令牌立即失效。
短有效期能缩短这个窗口,不能把窗口直接变成零。
需要即时吊销,仍然要让业务接口检查相应的会话或吊销状态。
顺便再补一个容易写错的地方:Redis 续期,不等于 JWT 续期。
JWT 里的 exp 已经被签名保护。把 Redis 的 TTL 延长,并不会改变客户端那张 JWT 的过期时间。需要延长访问资格,就应该按认证流程签发新的访问令牌,而不是只改 Redis,然后忽略 JWT 的过期校验。
这几个时间最好在设计时就写清楚:访问令牌多久过期、登录会话保留多久、刷新资格什么时候结束。
否则,用户一直在操作却突然掉线,排查起来就会发现,几套过期逻辑各算各的。
面试时,别只回答“因为 Redis 快”
把前面这些想清楚,回答就不用靠背概念撑场面了。
结合自己的项目,可以这样说:
我们使用 Redis 管理登录会话,是因为业务要求退出登录、账号封禁和主动踢下线,对后续请求及时生效。
如果使用 JWT,会先完成签名、有效期、签发方和接收方等校验,再检查服务端会话状态。所以这是一套有状态的认证方案,不是纯粹的无状态 JWT。
代价是增加了查询开销和对 Redis 的依赖,需要处理超时、过期策略及状态丢失。无法确认登录态时,不能直接对受保护接口放行。
如果 JWT 没有承担额外作用,只是用来索引 Redis 会话,我会考虑改用随机 Token,让方案更简单。
这样的回答,不需要证明 JWT 和 Redis 谁更高级,也不用急着跟面试官争输赢。
他说“既然查 Redis,为什么还用 JWT”,你应该能解释 JWT 提供了什么。
他说“JWT 不是无状态吗”,你应该能解释为什么业务需要保存状态。
他说“Redis 挂了怎么办”,你应该能说出请求会怎么处理,而不是继续强调 Redis 很快。
Token 存在哪里并不难回答。真正要说清楚的是:用户已经退出、账号已经被封,系统到底从什么时候开始不再认这张凭证。
如果对 Redis 会话管理、JWT 校验这些细节还想系统梳理一遍,也可以去云栈社区翻一翻相关讨论和实战案例,把认证链路里的每一个状态流转都吃透。
