# 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 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` - 修改 `MobileLogin` 返回 `ApiResponse` - 保持向后兼容(同时返回 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 天,可根据需要调整