面试中被嘲笑Token放在Redis里,怎么应对?

知乎 2026-04-09 10:14:34
最近,小编在知乎上看到这样一个问题:

 

 
 

面试中被嘲笑Token放在redis里,该如何应对这种情况呢?

 
 
 

 

 

秉持着和平交流的学习态度,小编精选了几位高赞知乎网友的精彩回答,分享给大家学习交流(勿上升、勿引战):

 

 

 

1号网友:MicroOps

 

 

 

你就问他代码上线前有没有做review,有没有做灰度发布、蓝绿发布,每次上线有没有做回归测试,有没有定期做渗透测试、漏洞扫描,安全漏洞有没有做定期修复,生产环境有没有做网络隔离(划分DMZ、内网),有没有准入控制,程序配置文件中密码字段有没有加密,敏感数据落盘(包含日志、数据库)有没有做脱敏和加密。

 

如果他们公司有一条没做到,就怼他: 垃圾公司。

 

如果他们公司都做到了,那你的确无话可说。

 

现在主流的Token方案主要是两种。

 

第一种是传统的cookie/session方案,工作原理就是服务器生成一个随机会话ID, 并下发给客户端,此方案简单,但是对于分布式、多副本需要用例如redis、mysql之类的服务进行数据共享。直接存token不是什么大问题,但是如果遇到数据库数据泄露可能会导致攻击者通过token登陆到后台,解决方案有很多,比较简单的做法就是存token的hash值,这样可以避免因数据泄露导致的身份伪造。

 

第二种就是jwt方案,此方案最大优势就是无状态,不用保存会话信息就可以实现分布式、多副本。但缺点是没有会话列表以及吊销会话困难。如果有人token被泄露了,要么等token过期,要么修改jwt密钥让所有会话失效。想要解决此问题,通常就需要引入redis、mysql之类的服务存储token信息,可以将所有已登录的token信息存入数据库,吊销时删除相关token信息,也可以建立token黑名单,将吊销的token信息存入此黑名单。但是直接存入完整token也可能存在方案一类似的风险,解决方案存hash或者是在payload中插入一个tokenid字段,数据库只记录id字段,这样就可以避免因数据泄露导致的身份伪造。

 

对于token直接入库我没有任何否认的意思,每个公司/项目所需要的安全程度不一样,你们项目如果能接受这个风险,完全可以直接入库。我提到的存token的hash或jwt的tokenid,只是基于存在的风险点,提供了一点建议。存token还是存hash,无非就是一行代码的事情。

 

如果你秉着技术探讨的态度说token入库完全没有风险,那我可以给你探讨探讨,否则,可以忽略我的论点:

 

按照问题中所说的token放redis,从安全角度来说:

 

1、我们不能保证所有维护的人都能有这个觉悟,保证redis只能内网访问,并且都有强口令保护,恰好我们公司另一个团队,以前就出过这样一个事情:redis直接允许公网访问,密码还是弱口令,结果服务器遭挖矿,数据倒是没有泄露。这样的事情我在很多技术群(QQ群)里,看到类似的案例。

 

2、我们不能保证redis所在的内网,都拥有固若金汤的防火墙规则。恰好我们公司另一个团队又出过类似的事情,为了方便调试把服务器的docker远程控制端口开放到公网,还不需要任何认证就可以使用,结果也惨遭挖矿。如果黑客当时通过横向渗透,我相信可以拿下其他一些服务器的权限,因为很多公司(包括我们公司),内网之间的防护做的并不是特别安全,拿下redis服务器权限也不是不可能。

 

3、你没法保证你们开放到公网的所有服务都绝对安全,例如以前的fastjson漏洞,或者你的程序存在SQL注入漏洞、任意命令执行漏洞等。

 

或许你认为你不会存在这些问题,但你不能保证你没有猪队友。 你或许会认为出现问题再修复,只要不是你的token自身的问题就不归你管。那我只能说,想法没错,继续保持。

 

 

 

2号知乎网友:netkiller

 

 

 

面试官的脑回路大概是这样的:

 

“Token(尤其是 JWT)设计的初衷就是无状态(Stateless)。哎,服务器只要解密签名就知道你是谁,不需要查库。你把它塞进 Redis,不就又变成 Session 模式了吗?那你还用 Token 干嘛?这不是脱裤子放屁吗?”

 

教科书上确实是这么写的。

 

但教科书不会告诉你:如果用户手机丢了,想把这个账号强制下线,纯无状态的 JWT 怎么做?

 

答案是:做不到。

 

 除非你换密钥,让所有用户一起掉线。

 

为什么要存 Redis?

 

告诉面试官,把 Token 存 Redis(或者只存 Token 的 ID),不是为了认证,而是为了管理。

 

我给你总结一下回答的话术,这样是不是合理一点。

 

1、并没有绝对的无状态,只有可控的状态

 

话术:

 

“面试官您说得对,JWT 本身确实是无状态的。但在我们的业务场景里,安全管控的需求高于无状态的需求。我们需要实现一键踢人、多端登录限制(只允许一个手机在线)、修改密码后强制旧 Token 失效等功能。如果不存 Redis 做白名单或黑名单机制,纯无状态的 JWT 无法满足这些业务刚需。”

 

2、续签的体验问题

 

话术:

 

“如果纯靠 JWT 的 exp 字段,用户用着用着突然过期了,体验很差。我们需要实现滑动过期(用户一直在用,Token 就一直不过期)。把 Token 存 Redis 并设置 TTL,用户每次请求时刷新 TTL,是实现滑动过期成本最低的方案。否则就得引入复杂的 Refresh Token + Access Token 双令牌机制,对于我们当时的团队规模和并发量来说,Redis 方案性价比最高。”

 

3、性能权衡

 

话术:

 

“确实,查 Redis 有网络开销。但 JWT 的非对称加密验证(如 RSA)是非常消耗 CPU 的。在并发并没有达到数万 QPS 的情况下,Redis 的毫秒级读取对性能的影响微乎其微,但它带来的业务灵活性(随时封禁、统计在线人数)是纯 CPU 计算换不来的。”

 

如果面试官说:“那你可以用 Refresh Token 存 Redis,Access Token 不存啊?”

 

这时候你要承认这是更优解,但要强调演进过程。

 

话术:

 

“您说的双 Token 方案确实是标准的 OAuth2 做法,适合更大规模的系统。

 

但我们当时考虑到:

 

1、前后端交互的复杂度(前端要写拦截器处理 401 自动刷新)。

 

2、Redis 集群极其稳定,并不是瓶颈。

 

所以我们选择了以空间换复杂度的 Reference Token 模式(或者 Token 强校验模式)。架构没有最好的,只有最适合当下的。在那个阶段,这个方案帮我们快速实现了业务且没出过事故。”

 

 

 

3号知乎网友:亮剑ch

 

 

 

我最近接到个项目,其中有个需求就是后台如果30分钟内没有任何操作,token就失效要重新登录,我想到办法就是用redis存储token的上次操作时间并设置redis的过期时间(与token的过期时间保持一致),有操作时更新redis保存的时间,如果发现上次时间已经过了30分钟就返回失效,除了用redis这个方法我想不到其他办法。

 

 

 

4号知乎网友:竹露晨曦

 

 

 

Token放在redis是一种方案,JWT也是一种方案。所有的方案都是为了需求服务,脱离需求说方案都是瞎扯淡。

 

如果面试的人觉得JWT好,你就问他如果JWT发出去后,如果发生了安全问题,怎么从服务端主动失效。

 

Redis优点是服务端强安全管控,缺点是高并发时需要更多资源;JWT优点是无状态、对于需要跨域认证和高性能的场景友好,缺点是安全性较差,需要被动等待失效。

 

当然有时候会把二者结合起来用,这一切都取决于具体的需求场景。用Redis没错,用JWT也没错,你要认为JWT比Redis高雅,那就错了。

 

 

 

5号知乎网友:花宝宝

 

 

 

Token 放 Redis 被嘲笑,通常是面试官觉得这么做不懂 JWT。JWT 的卖点就是无状态——服务端不用存任何东西,token 里自带用户信息和签名,拿到之后验证签名就行,不需要查数据库也不需要查 Redis。

 

听起来很完美,然后上线了。

 

产品经理跑过来说:有个用户密码被盗了,要立刻把他踢下线。

 

纯 JWT 方案,token 签发的时候设了 2 小时过期。被盗的 token 还有 1 小时 45 分钟才过期。这 1 小时 45 分钟里,拿着这个 token 的人可以用被盗账号做任何事。

 

已经签发的 JWT 没有任何办法立刻失效。“无状态”意味着服务端不记得自己发过哪些 token,自然也没法说“这个 token 作废了”。

 

上线第一天就撞上这个问题的团队不在少数。

 

主动踢人下线做不到。

 

不只是密码被盗。后台管理员要封禁一个违规用户、用户自己修改了密码想让其他设备全部下线、用户点了“退出登录”——这些场景都需要让一个已签发的 token 立刻失效。

 

纯 JWT 做不到。

 

为了解决这个问题,只能加一层存储——维护一个“黑名单”。用户被踢下线的时候把 token 加到黑名单里,每次请求来了先查黑名单。

 

黑名单存哪?内存不行,重启就丢了,而且多个服务实例之间不共享。数据库太慢,每个请求都查一次数据库受不了。

 

存 Redis。

 

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
public void logout(String token) {    long expiration = jwtUtil.getExpiration(token);    long ttl = expiration - System.currentTimeMillis();    if (ttl > 0) {        redisTemplate.opsForValue().set("blacklist:" + token, "1", ttl, TimeUnit.MILLISECONDS);    }}public boolean isTokenValid(String token) {    if (redisTemplate.hasKey("blacklist:" + token)) {        return false;    }    return jwtUtil.verify(token);}

 

到这一步,“无状态 JWT”已经不是无状态了。每个请求都要查一次 Redis。

 

token 续期也是个问题。

 

用户正在页面上填一个很长的表单,填了 25 分钟,点提交。token 过期了,请求被拒绝,表单内容全丢了。

 

常见的做法是双 token:AccessToken 有效期短(比如 30 分钟),RefreshToken 有效期长(比如 7 天)。AccessToken 过期了,前端用 RefreshToken 去换一个新的 AccessToken。

 

RefreshToken 存哪?存 Cookie 可以,但 RefreshToken 要不要支持主动吊销?要的话——又回到 Redis。

 

另一种是“滑动过期”。用户每次请求都刷新 token 的过期时间。但 JWT 的过期时间写在 payload 里,改了过期时间整个 token 就变了,等于每次请求都签发一个新 token。而且旧 token 在过期之前仍然有效——没法让它失效,除非……加黑名单,存 Redis。

 

怎么绕都绕不开 Redis。

 

JWT 的“无状态”在什么时候是真正的优势?跨服务调用

 

微服务架构里,用户请求经过网关之后要调用户服务、订单服务、支付服务。如果用传统 Session,每个服务都要去 Redis 查一次 Session 信息。如果用 JWT,网关验证完签名之后把用户信息往下传就行了,下游服务不需要再查任何存储。

 

用户请求 → 网关(验证 JWT 签名)→ 订单服务(直接从 JWT 解析 userId)→ 支付服务(直接从 JWT 解析 userId)

 

这种场景下 JWT 的无状态确实省了很多事。但注意,这里 JWT 承担的角色是服务间传递用户身份,不是做登录会话管理。网关那一层照样可以用 Redis 管理用户的登录状态,只是下游服务不需要再查了。

 

另一个适合 JWT 的场景是一次性的凭证——邮箱验证链接、密码重置链接、临时分享链接。签发一次,用一次,不需要续期也不需要主动吊销。这才是 JWT 自包含特性最舒服的地方。

 

回到被嘲笑的点,Token 放 Redis 的”问题”是什么?

 

性能? Redis 单次查询不到 1ms,单机 QPS 十几万。服务能扛一万并发的时候,Redis 那层完全不是瓶颈。

 

单点故障? Redis Sentinel 或 Redis Cluster 做高可用,主节点挂了自动切换。Session 存 Redis 是业界跑了十几年的成熟方案,从来没有人说“Session 不能放 Redis 因为会单点故障”。

 

违背了 JWT 的设计理念? 这倒是真的。生成一个 JWT 然后把它整个存进 Redis,每次验证都去 Redis 查而不是验签名——那确实只是用了 JWT 的格式,没用它的能力。这种情况下不如直接生成一个随机字符串当 Session ID,还省了 JWT 编解码的开销。

 

面试官嘲笑的可能就是这个:用了 JWT 但完全没利用无状态特性,那为什么要用 JWT?这个问题确实值得想清楚。

 

但 Token 该不该放 Redis,取决于业务需求

 

系统需要主动踢人下线、修改密码后其他设备失效、管理员封禁用户 —— 必须有一个中心化的状态存储。Redis 是最合适的选择。至于 token 的格式是 JWT 还是随机字符串,反而是次要的。

 

系统不需要这些,纯粹是用户登录一次、token 过期了重新登录 —— 纯 JWT 没问题,省一层 Redis 依赖。

 

大部分业务系统都需要前者。用户管理后台总得有个“强制下线”的按钮吧?

 

整理丨dbaplus社群

来源丨网址:https://www.zhihu.com/question/12853133755?share_code=W4zp0bCi3qD1&utm_psn=2020537286345900648

*仅为提供参考和学习交流,不代表dbaplus社群立场!dbaplus社群欢迎广大技术人员投稿,投稿邮箱:editor@dbaplus.cn

最新评论
访客 2024年04月08日

如果字段的最大可能长度超过255字节,那么长度值可能…

访客 2024年03月04日

只能说作者太用心了,优秀

访客 2024年02月23日

感谢详解

访客 2024年02月20日

一般干个7-8年(即30岁左右),能做到年入40w-50w;有…

访客 2023年08月20日

230721

活动预告