143 lines
5.3 KiB
Markdown
143 lines
5.3 KiB
Markdown
# Implementation Plan: Refresh Token 机制
|
||
|
||
## Overview
|
||
|
||
实现双 Token 认证机制,分为后端改动和前端改动两个阶段。后端先完成数据库、实体、服务和接口的改动,前端再实现自动刷新逻辑。
|
||
|
||
## Tasks
|
||
|
||
- [x] 1. 后端:数据库和实体层
|
||
- [x] 1.1 创建 UserRefreshToken 实体类
|
||
- 在 `HoneyBox.Model/Entities/` 目录下创建 `UserRefreshToken.cs`
|
||
- 包含 Id、UserId、TokenHash、ExpiresAt、CreatedAt、CreatedByIp、RevokedAt、RevokedByIp、ReplacedByToken 字段
|
||
- 添加计算属性 IsExpired、IsRevoked、IsActive
|
||
- 添加与 User 表的外键关联
|
||
- _Requirements: 5.1, 5.2_
|
||
|
||
- [x] 1.2 更新 DbContext 添加 UserRefreshTokens DbSet
|
||
- 在 `HoneyBoxDbContext.cs` 中添加 `DbSet<UserRefreshToken> UserRefreshTokens`
|
||
- 配置表名和索引
|
||
- _Requirements: 5.1_
|
||
|
||
- [x] 1.3 创建数据库迁移脚本
|
||
- 创建 `create_user_refresh_tokens.sql` 脚本
|
||
- 包含表创建、索引和外键约束
|
||
- _Requirements: 5.1, 5.2_
|
||
|
||
- [x] 2. 后端:模型和接口层
|
||
- [x] 2.1 创建 LoginResponse 模型
|
||
- 在 `HoneyBox.Model/Models/Auth/` 目录下创建 `LoginResponse.cs`
|
||
- 包含 AccessToken、RefreshToken、ExpiresIn 字段
|
||
- _Requirements: 1.1, 1.2_
|
||
|
||
- [x] 2.2 创建 RefreshTokenRequest 和 RefreshTokenResult 模型
|
||
- 创建请求模型包含 RefreshToken 字段
|
||
- 创建结果模型包含 Success、LoginResponse、ErrorMessage 字段
|
||
- _Requirements: 2.1_
|
||
|
||
- [x] 2.3 扩展 IAuthService 接口
|
||
- 添加 `RefreshTokenAsync` 方法
|
||
- 添加 `RevokeTokenAsync` 方法
|
||
- 添加 `RevokeAllUserTokensAsync` 方法
|
||
- _Requirements: 2.1, 4.4_
|
||
|
||
- [-] 3. 后端:服务层实现
|
||
- [x] 3.1 实现 Refresh Token 生成和存储逻辑
|
||
- 在 AuthService 中添加 `GenerateRefreshToken` 私有方法
|
||
- 使用 SHA256 哈希存储 Token
|
||
- 设置 7 天有效期
|
||
- _Requirements: 1.4, 1.5, 4.1_
|
||
|
||
- [x] 3.2 修改登录方法返回双 Token
|
||
- 修改 `WechatMiniProgramLoginAsync` 返回 LoginResponse
|
||
- 修改 `MobileLoginAsync` 返回 LoginResponse
|
||
- 调用 GenerateRefreshToken 生成并存储 Refresh Token
|
||
- _Requirements: 1.1, 1.2, 1.3, 1.4, 1.5_
|
||
|
||
- [x] 3.3 实现 RefreshTokenAsync 方法
|
||
- 验证 Refresh Token 有效性(未过期、未撤销)
|
||
- 实现 Token 轮换(撤销旧 Token,生成新 Token)
|
||
- 记录 ReplacedByToken 关联关系
|
||
- _Requirements: 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 5.3_
|
||
|
||
- [x] 3.4 实现 RevokeTokenAsync 方法
|
||
- 根据 Token 哈希查找并撤销
|
||
- 记录撤销时间和 IP
|
||
- _Requirements: 4.4_
|
||
|
||
- [ ]* 3.5 编写属性测试:登录响应结构完整性
|
||
- **Property 1: 登录响应结构完整性**
|
||
- **Validates: Requirements 1.1, 1.2**
|
||
|
||
- [ ]* 3.6 编写属性测试:Token 轮换完整性
|
||
- **Property 6: Token 轮换完整性**
|
||
- **Validates: Requirements 2.5, 2.6**
|
||
|
||
- [x] 4. Checkpoint - 后端服务层完成
|
||
- 确保所有测试通过,ask the user if questions arise.
|
||
|
||
- [x] 5. 后端:控制器层
|
||
- [x] 5.1 修改 AuthController 登录接口返回格式
|
||
- 修改 `WechatMiniProgramLogin` 返回 `ApiResponse<LoginResponse>`
|
||
- 修改 `MobileLogin` 返回 `ApiResponse<LoginResponse>`
|
||
- 保持向后兼容(同时返回 token 字段)
|
||
- _Requirements: 1.1, 1.2, 6.1_
|
||
|
||
- [x] 5.2 新增 Token 刷新接口
|
||
- 添加 `POST /api/refresh` 端点
|
||
- 接收 RefreshTokenRequest,返回 LoginResponse
|
||
- 处理各种错误情况
|
||
- _Requirements: 2.1, 2.2, 2.3, 2.4_
|
||
|
||
- [x] 5.3 新增 Token 撤销接口(可选,用于退出登录)
|
||
- 添加 `POST /api/logout` 端点
|
||
- 撤销用户的 Refresh Token
|
||
- _Requirements: 4.4_
|
||
|
||
- [x] 6. Checkpoint - 后端完成
|
||
- 确保所有测试通过,ask the user if questions arise.
|
||
- 使用 Postman 或 curl 测试接口
|
||
|
||
- [x] 7. 前端:Token 存储改造
|
||
- [x] 7.1 修改登录成功后的 Token 存储逻辑
|
||
- 存储 accessToken 和 refreshToken 到 uni.storage
|
||
- 计算并存储 tokenExpireTime
|
||
- _Requirements: 4.2_
|
||
|
||
- [x] 7.2 修改退出登录清除 Token 逻辑
|
||
- 清除 accessToken、refreshToken、tokenExpireTime
|
||
- 调用后端撤销接口(可选)
|
||
- _Requirements: 4.3_
|
||
|
||
- [x] 8. 前端:自动刷新机制
|
||
- [x] 8.1 实现 refreshToken 方法
|
||
- 调用 `/api/refresh` 接口
|
||
- 更新本地存储的 Token
|
||
- 返回刷新结果
|
||
- _Requirements: 3.1, 3.2_
|
||
|
||
- [x] 8.2 实现请求队列机制
|
||
- 添加 isRefreshing 状态标记
|
||
- 添加 refreshQueue 请求队列
|
||
- 刷新完成后依次执行队列中的请求
|
||
- _Requirements: 3.5, 3.6_
|
||
|
||
- [x] 8.3 修改 request 方法处理 401 自动刷新
|
||
- 检测 401 响应触发刷新
|
||
- 刷新成功后重试原请求
|
||
- 刷新失败后跳转登录页
|
||
- _Requirements: 3.1, 3.3, 3.4_
|
||
|
||
- [x] 9. Final Checkpoint - 全部完成
|
||
- 确保所有测试通过,ask the user if questions arise.
|
||
- 端到端测试:登录 → 等待过期 → 自动刷新 → 继续使用
|
||
|
||
## Notes
|
||
|
||
- Tasks marked with `*` are optional and can be skipped for faster MVP
|
||
- 后端改动需要先执行数据库迁移脚本
|
||
- 前端改动需要在后端接口完成后进行
|
||
- 建议先在测试环境验证,再部署到生产环境
|
||
- Access Token 有效期设置为 30 分钟,可根据需要调整
|
||
- Refresh Token 有效期设置为 7 天,可根据需要调整
|