You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于JWT实现多设备同时登录的令牌管理(NestJS后端)

问题根源

你当前的设计将refresh token与用户表记录做1:1强绑定,本质是面向单设备登录的模型,多设备场景下token互相覆盖是模型的天然缺陷,和接口逻辑代码无关。

工业界标准落地方案

1. 重构refresh token存储模型

绝对不要把多个设备的token存在用户表的单个字段、甚至是用户表字段存JSON数组,后者会带来查询效率低、无法加索引、并发写丢数据、过期清理困难等一系列生产问题。
单独新建user_refresh_tokens关联表,和用户表做多对一映射(一个用户对应多条有效token记录,每条记录对应一个登录设备),核心字段如下:

  • id:表主键
  • user_id:关联用户表的外键,必须加普通索引
  • device_id:客户端持久化存储的唯一设备标识(web端可首次访问时生成随机UUID存localStorage,移动端直接取系统级设备UUID),同设备所有登录、刷新请求固定携带该标识
  • token_hash:存储refresh token的哈希值,禁止存明文
  • expires_at:refresh token过期时间戳
  • issued_at:token签发时间
  • ip:token签发时的客户端IP,可选,用于安全审计
  • user_agent:token签发时的客户端UA,可选,用于前端展示登录设备信息
  • is_revoked:布尔值,标记token是否被手动吊销,默认值为false

2. 调整登录接口(/api/login)逻辑

  1. 校验用户名、密码合法性通过后,要求客户端必须携带device_id参数
  2. 调用jwt库分别生成access token、refresh token,签发refresh token时payload固定携带sub: userid、deviceId: 客户端传入的device_id、jti: 随机生成的UUID三个核心字段
  3. 对生成的refresh token用bcrypt/argon2做哈希(和密码哈希的安全等级一致,禁止用MD5、SHA256等快速哈希算法)
  4. 查询user_refresh_tokens表中是否存在user_id = 当前用户ID且device_id = 客户端传入设备ID的记录:
    • 若存在记录:更新该条记录的token_hash、expires_at、ip、user_agent字段,覆盖同设备旧的token信息,避免同设备重复登录产生冗余记录
    • 若不存在记录:插入一条新的token记录
  5. 将access token、refresh token返回给客户端

3. 调整令牌刷新接口(/api/refresh)逻辑

  1. 接口要求客户端同时提交refresh token明文、当前设备的device_id
  2. 先校验refresh token的JWT格式合法性、是否已过JWT自身的有效期,从payload中提取userid、deviceId、jti
  3. 到user_refresh_tokens表查询匹配以下条件的记录:user_id = 提取的用户ID、device_id = 客户端提交的设备ID、is_revoked = false、expires_at > 当前服务器时间
  4. 用客户端提交的refresh token明文,和查询到的记录中的token_hash做哈希校验:
    • 校验不通过直接返回401状态码,可配套安全策略:同一账号短时间内出现多次校验失败时,触发异常登录告警
    • 校验通过后,生成新的access token、新的refresh token
  5. 更新当前匹配到的token记录:将token_hash替换为新refresh token的哈希值,若业务用滑动过期策略则同步延长expires_at,固定过期策略则保持原过期时间不变
  6. 将新生成的两个令牌返回给客户端

4. 配套必备能力

  • 单设备登出:调用/api/logout接口时,直接将当前user_id + device_id对应的记录is_revoked字段设为true,仅下线当前设备,不影响其他已登录设备
  • 登录设备管理:提供查询接口,返回当前账号下所有有效token对应的设备信息(UA、登录IP、登录时间),支持用户手动指定设备下线,本质就是将对应记录的is_revoked设为true
  • 过期数据清理:配置每日定时任务,物理删除表中expires_at早于当前时间超过30天、或is_revoked = true超过7天的记录,避免表数据无限膨胀
  • 高危操作联动:用户修改密码、主动触发"下线所有其他设备"操作时,批量将当前账号下除当前设备外的所有token记录is_revoked设为true,强制其他设备重新登录
  • 泄露防护:如果刷新接口时出现token哈希校验不通过的情况,直接将当前匹配到的device_id对应记录标记为吊销,避免被窃取的token被恶意利用
NestJS落地注意点
  • 用@nestjs/jwt签发token时,access token建议设置15-30分钟有效期,refresh token建议设置7-30天有效期,根据业务安全等级调整
  • refresh token的payload不要存敏感信息,JWT payload仅做Base64编码,可被直接解码,敏感数据必须存在服务端数据库
  • 不要把refresh token的校验逻辑全写在控制器里,封装成独立的Passport Strategy复用逻辑,和现有JWT鉴权体系保持一致

内容的提问来源于stack exchange,提问作者Kunal Karmakar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.31 10:27:08