为自有App实现「记住我」功能的简易安全AccessToken过期处理方案
最简安全实现方案:基于现有会话表新增Refresh Token机制
不用引入完整OAuth组件,直接在现有sessions表基础上扩展,核心是新增refresh_token实现"记住我"功能,具体步骤如下:
1. 数据库表扩展
在现有sessions表中新增3个字段:
refresh_token: 字符串类型(建议长度≥64),存储唯一的刷新令牌,需设置唯一索引refresh_expiry: datetime类型,存储refresh_token的过期时间(建议设为90天,比access_token的1周更长)is_remembered: 布尔类型,标记该会话是否由"记住我"生成(可选,方便后续统计或管理)
2. 修改原有/api/access_token接口
- 新增请求参数
remember_me(布尔值,默认false) - 验证
email和password通过后,保持原有access_token生成逻辑(有效期1周)不变 - 如果
remember_me为true:- 用密码学安全的随机算法生成refresh_token(比如
secrets.token_hex(32)或bin2hex(random_bytes(32))) - 将
refresh_token、refresh_expiry(当前时间+90天)写入sessions表对应记录
- 用密码学安全的随机算法生成refresh_token(比如
- 返回结果新增
refresh_token字段(仅当remember_me=true时返回)
3. 新增/api/refresh_token接口
这个接口用来在access_token过期时,无需密码即可获取新的access_token:
- 请求参数:
refresh_token - 验证逻辑:
- 检查
sessions表中是否存在该refresh_token,且refresh_expiry未过期 - 确认对应的用户状态正常(未封禁、未删除等)
- 检查
- 验证通过后:
- 生成新的
access_token,更新sessions表中的access_token和expiry字段(重置为当前时间+1周) - 可选:滚动更新
refresh_expiry为当前时间+90天(提升用户体验,避免90天后强制登录)
- 生成新的
- 返回新的
access_token,可选返回更新后的refresh_token(如果滚动过期的话)
4. 关键安全细节
- refresh_token的生成:必须使用密码学安全的随机生成器,避免可预测的字符串,防止被暴力破解
- 传输安全:所有接口必须通过HTTPS访问,防止token被中间人窃听
- 客户端存储:
- 移动端:将refresh_token存储在系统安全容器(iOS Keychain、Android Keystore),禁止明文存储在本地文件或SharedPreferences
- Web端:将refresh_token存入
HttpOnly、Secure、SameSite=Strict的Cookie中,避免XSS攻击窃取
- 失效机制:
- 提供登出接口,调用时清空
sessions表中对应记录的refresh_token和access_token - 支持用户主动失效所有refresh_token(比如账号设置里的"登出所有设备")
- 限制单用户的refresh_token数量(比如最多5个),超出时自动删除最早生成的token,防止滥用
- 提供登出接口,调用时清空
- 过期策略:refresh_token有效期不要设得过长(90天是比较平衡的选择),即使泄露也能限制危害时长
5. 客户端逻辑适配
- 用户登录时,若勾选"记住我",则本地保存refresh_token;否则仅保存access_token
- 当接口返回
401 Unauthorized(access_token过期)时,自动调用/api/refresh_token接口获取新的access_token,无需用户手动登录 - 若
/api/refresh_token返回过期错误(比如403),再引导用户进入登录页面重新输入账号密码
内容的提问来源于stack exchange,提问作者Ryan
相关产品推荐
相关产品推荐

