JWT鉴权到底做了什么?

zijieLeo
19 分钟
7 次浏览
JWT鉴权到底做了什么?

先看流程图(成熟版:access + refresh + Redis)



1)执行主体清单:谁对谁做了什么

  • 执行主体:用户

    • 作用对象:前端
    • 动作:输入账号/密码、点击登录、触发敏感操作
  • 执行主体:前端(浏览器端应用)

    • 作用对象:后端接口、浏览器存储
    • 动作:发起登录请求、保存 token、后续请求携带 token、在页面侧做路由守卫(更多是体验层)
  • 执行主体:后端(登录接口 / 刷新接口 / 业务接口)

    • 作用对象:数据库、Redis、JWT 签名验签、请求上下文
    • 动作:校验凭证、签发 token、刷新 token、鉴权与授权、输出错误码
  • 执行主体:数据库

    • 作用对象:用户/角色/状态等数据
    • 动作:查用户、取密码哈希、取角色、判断是否禁用/锁定
  • 执行主体:Redis

    • 作用对象:会话状态、限流计数、撤销/黑名单、并发刷新控制
    • 动作:存 refresh 会话、做 rate limit、做 refresh 轮换、做“踢下线/封禁”即时生效

2)为什么要 Redis:成熟流程里它在干什么

JWT 的问题不在“验签”,而在“签发之后怎么管”。

2.1 解决“撤销”这件事

JWT 自包含,只要没过期,单靠验签就会通过。现实里经常要:

  • 改密码要立刻让旧登录态失效
  • 封号要立刻生效
  • 发现异常登录要踢下线

Redis 常见落点:

  • refresh_token 会话落 Redis(最常见)

    • access_token 设短(比如 5~15 分钟)
    • refresh_token 设长(比如 7~30 天)
    • 每次 refresh 都要查 Redis:会话不存在/被撤销 → 刷新失败 → 登录态结束
    • 这样“长期登录态”是可控的,不靠 JWT 自己硬扛
  • 每次请求查 Redis(更强控制)

    • JWT payload 带 sessionId/jti/version
    • Redis 维护该用户当前有效会话/版本
    • 每次请求验签后再查 Redis,不在白名单就拒绝
    • 代价是多一次 Redis 读,但换来“想让它立刻失效就立刻失效”

2.2 做风控:限流 + 并发刷新控制

  • 登录限流:防爆破(计数 + TTL)
  • 刷新并发锁:同一时间多个请求同时刷新,容易把 refresh rotation 搞乱,用 Redis 锁最稳
  • 黑名单/异常标记:检测到 refresh 被复用(疑似泄漏)直接封掉会话

3)双 Token(access + refresh):为什么成了主流

单 token(只一个 JWT)

  • 优点:简单
  • 缺点:要么过期短体验差,要么过期长泄漏代价大;撤销困难

双 token(access 短 + refresh 长)

  • 优点
    • access 泄漏窗口小
    • access 过期可静默刷新,体验好
    • refresh 可撤销(靠 Redis/数据库会话),能踢下线
  • 缺点
    • 工程复杂度上来:刷新接口、rotation、并发刷新、异常处理

成熟系统看起来“顺滑”,通常就是因为 refresh 这条链路做得扎实。


4)Token 放哪:为什么会牵扯 XSS/CSRF(原理 + 防法)

这是选择题:你选的存储位置,会把风险偏向不同方向。

4.1 放 localStorage:更怕 XSS

  • XSS 怎么发生:页面里有恶意脚本执行(用户输入没消毒、富文本、第三方脚本、Markdown 渲染等)
  • 为什么能偷 token:token 在 localStorage,JS 直接读出来就能发走
  • 怎么防(核心原理)
    • 不让“数据变成脚本”:严格消毒/转义
    • CSP 把脚本来源钉死,尽量禁 inline
    • 第三方脚本和依赖治理
    • 富文本/Markdown 渲染特别要小心
  • HttpOnly 的意义:JS 读不到 cookie 值,所以 XSS 很难直接把 token 字符串掏走
  • CSRF 为什么会来:浏览器会自动携带 Cookie;攻击者诱导用户访问恶意站点,那个站点向你后端发请求,浏览器可能会带上 Cookie
  • 怎么防(核心原理)
    • SameSite=Lax/Strict:减少跨站自动携带
    • CSRF Token:攻击者拿不到你站点生成的随机 token
    • 校验 Origin/Referer:跨站来源能暴露出来

4.3 不同场景的常见选择(更贴近真实工程)

  • 高价值账户(金融/支付/企业核心后台)
    • 多见:Cookie + HttpOnly + SameSite + CSRF Token + 强 CSP
    • 逻辑很朴素:宁愿把 CSRF 这套工程成本背起来,也尽量别让 token 暴露在 JS 可读的位置
  • 内容型产品 / 个人博客后台
    • 两种都能跑:
      • localStorage + Authorization:实现快,但要把 XSS 入口盯紧
      • HttpOnly Cookie:更抗“偷 token”,但 CSRF 防护要配齐
  • 移动端 App
    • 用系统安全存储(Keychain/Keystore),CSRF 不是典型问题,但仍要防本地泄漏与重放

5)NestJS / Java 对比:本质做的是同一件事

  • 执行主体:NestJS

    • 用 Strategy/Guard 把“提取 token → 验签 → 注入当前用户 → 授权”组件化
    • Redis 常用于:session、rate limit、refresh rotation、blacklist
  • 执行主体:Java(Spring Security)

    • 用 Filter 链把“提取 token → 验签 → 写入安全上下文 → 授权规则”做成全局统一
    • Redis 常用于:分布式会话、token 撤销、限流、风控状态

换掉框架名,动作完全一致:每个请求先过鉴权层,鉴权层决定你是谁、能不能做这个事。


结尾:我现在判断“JWT 鉴权成熟不成熟”,就看三点

  1. access 是否短命、refresh 是否可控(能撤销、能轮换)
  2. token 存储策略是否和 XSS/CSRF 防线匹配
  3. Redis 是否承载了会话与风控状态(否则很难“管理登录态”)

这三点做齐,JWT 才不只是“能登录”,而是“能长期稳定跑”。

评论

登录后即可发表评论

暂无评论,快来发表第一条评论吧!