JWT新手求教:数据库存储Refresh Token及多设备登出场景处理
关于Refresh Token的多设备处理与数据库存储问题
一、多设备登录/登出时是否需要撤销Refresh Token?
- 多设备登录场景:除非产品明确要求「单设备独占登录」(比如部分金融类APP),否则不需要主动撤销其他设备的Refresh Token。用户在手机、电脑等多端同时登录是常见需求,保留各设备的有效Token能提升用户体验。如果是敏感系统,可在新设备登录时,将该用户名下所有旧Refresh Token标记为已撤销,强制单设备在线。
- 登出操作场景:必须撤销当前设备对应的Refresh Token。不管是用户主动登出,还是账号被冻结、密码修改等被动登出情况,都要立即失效该Token——否则攻击者拿到这个Refresh Token后,仍能持续刷新获取AccessToken,造成安全隐患。
二、已有user_id、refresh_token列的表,如何优化存储Refresh Token?
仅靠这两列的表功能太有限,建议补充必要字段,同时遵循以下存储逻辑:
1. 补充关键字段
expires_at:记录Refresh Token的过期时间,避免Token永久有效。比如设置为7天有效期,之后即使未主动撤销,也会自动失效。同时可以定期清理过期记录,减轻数据库负担。is_revoked:布尔类型字段,标记该Token是否已被撤销。刷新AccessToken时,先检查这个字段,快速判断Token有效性。device_info:可选字段,记录设备标识(比如用户代理UA、设备ID),方便后续实现「查看登录设备」「退出其他设备」这类功能。- (可选)
created_at:记录Token创建时间,便于排查问题。
2. 核心存储流程
- 登录生成Token:用户登录验证通过后,生成Refresh Token,关联对应的
user_id,设置expires_at(比如当前时间+7天),is_revoked设为false,如果需要则填入device_info,最后插入数据库。 - 刷新AccessToken:用户用Refresh Token请求刷新时,先在数据库中查询该Token:检查是否存在、
expires_at是否未过期、is_revoked是否为false。验证通过后,再发放新的AccessToken;部分场景也可以同时生成新的Refresh Token,将旧Token标记为is_revoked=true。 - 登出撤销Token:用户登出时,根据
user_id和当前的refresh_token找到对应记录,将is_revoked设为true(也可以直接删除记录,但标记撤销更便于后续日志排查)。 - 定期清理过期Token:写定时任务(比如每天凌晨),删除
expires_at早于当前时间的记录,或者将其标记为过期。
3. 注意事项
- 索引优化:给
user_id加普通索引,方便快速查询某用户的所有Refresh Token;给refresh_token加唯一索引,避免重复存储相同Token。 - 存储方式:Refresh Token本身是经过签名的,不需要加密存储,但要确保数据库的访问权限严格控制,避免泄露。如果担心Token泄露后被直接使用,也可以存储Token的哈希值(比如用bcrypt算法),刷新时将请求的Token哈希后与数据库中的值比对——不过这种方式会增加一点性能开销,按需选择即可。
示例表结构(SQL)
CREATE TABLE refresh_tokens ( id INT AUTO_INCREMENT PRIMARY KEY, user_id INT NOT NULL, refresh_token VARCHAR(255) NOT NULL UNIQUE, expires_at DATETIME NOT NULL, device_info TEXT, is_revoked BOOLEAN DEFAULT FALSE, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE );
内容的提问来源于stack exchange,提问作者HOÀNG NGUYỄN VIỆT
相关产品推荐
相关产品推荐

