Files
junhong_cmp_fiber/openspec/changes/archive/2026-01-15-implement-b-end-auth-system/tasks.md
huang 18f35f3ef4 feat: 完成B端认证系统和商户管理模块测试补全
主要变更:
- 新增B端认证系统(后台+H5):登录、登出、Token刷新、密码修改
- 完善商户管理和商户账号管理功能
- 补全单元测试(ShopService: 72.5%, ShopAccountService: 79.8%)
- 新增集成测试(商户管理+商户账号管理)
- 归档OpenSpec提案(add-shop-account-management, implement-b-end-auth-system)
- 完善文档(使用指南、API文档、认证架构说明)

测试统计:
- 13个测试套件,37个测试用例,100%通过率
- 平均覆盖率76.2%,达标

OpenSpec验证:通过(strict模式)
2026-01-15 18:15:17 +08:00

605 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 实现任务清单
**Change ID**: `implement-b-end-auth-system`
---
## 阶段 1基础设施 (2-3 小时)
### Task 1.1: 创建 Token 管理器
**文件**: `pkg/auth/token.go`
**实现内容**:
- [x] 定义 `TokenManager` 结构体
- [x] 定义 `TokenInfo` 结构体(包含用户信息)
- [x] 实现 `GenerateTokenPair()`:生成 access token 和 refresh token
- [x] 实现 `ValidateAccessToken()`:验证 access token
- [x] 实现 `ValidateRefreshToken()`:验证 refresh token
- [x] 实现 `RefreshAccessToken()`:刷新 access token
- [x] 实现 `RevokeToken()`:撤销单个 token
- [x] 实现 `RevokeAllUserTokens()`:撤销用户的所有 token
**验证**:
- [x] 单元测试覆盖所有方法
- [x] Redis 连接失败时正确处理错误
- [x] Token 生成使用 UUID v4
- [x] Token 存储和查询正确
**依赖**: Redis 客户端
---
### Task 1.2: 创建认证常量
**文件**: `pkg/constants/auth.go`
**实现内容**:
- [x] 添加 `RedisAuthTokenKey()` 函数
- [x] 添加 `RedisRefreshTokenKey()` 函数
- [x] 添加 `RedisUserTokensKey()` 函数
- [x] 添加默认 Token TTL 常量
**验证**:
- [x] Redis key 格式正确
- [x] 无硬编码字符串
---
### Task 1.3: 扩展错误码
**文件**: `pkg/errors/codes.go`
**实现内容**:
- [x] 添加 `CodeInvalidCredentials = 1010`:用户名或密码错误
- [x] 添加 `CodeAccountDisabled = 1011`:账号已禁用
- [x] 添加 `CodeAccountLocked = 1012`:账号已锁定
- [x] 添加 `CodePasswordExpired = 1013`:密码已过期
- [x] 添加 `CodeInvalidOldPassword = 1014`:旧密码错误
- [x]`codeMessages``codeLevels` 中添加中文消息和日志级别
**验证**:
- [x] 所有新增错误码有对应的中文消息
- [x] 错误码不与现有冲突
---
## 阶段 2数据访问层 (1-2 小时)
### Task 2.1: 扩展 AccountStore
**文件**: `internal/store/postgres/account_store.go`
**实现内容**:
- [x] 添加 `GetByUsername()`:根据用户名查询账号
- [x] 添加 `GetByUsernameOrPhone()`:根据用户名或手机号查询
- [x] 确保查询包含软删除检查(`deleted_at IS NULL`
**验证**:
- [x] 查询条件正确
- [x] 单元测试覆盖新增方法
- [x] 已禁用账号无法查询
**依赖**: 无(已存在 AccountStore
---
## 阶段 3业务逻辑层 (4-6 小时)
### Task 3.1: 创建认证服务
**文件**: `internal/service/auth/service.go`
**实现内容**:
- [x] 定义 `Service` 结构体(注入 `AccountStore``TokenManager``Logger`
- [x] 定义 `LoginRequest``LoginResponse` DTO
- [x] 实现 `Login()`:账号密码登录
- [ ] 根据用户名查询账号
- [ ] 验证密码bcrypt.CompareHashAndPassword
- [ ] 检查账号状态status=1
- [ ] 生成 token 对
- [ ] 查询用户权限列表(调用 permission service
- [ ] 返回 token 和用户信息
- [x] 实现 `Logout()`:登出
- [ ] 撤销 access token
- [ ] 撤销 refresh token
- [x] 实现 `RefreshToken()`:刷新 token
- [ ] 验证 refresh token
- [ ] 生成新的 access token
- [x] 实现 `GetCurrentUser()`:获取当前用户信息和权限
- [x] 实现 `ChangePassword()`:修改密码
- [ ] 验证旧密码
- [ ] 哈希新密码
- [ ] 更新数据库
- [ ] 撤销所有旧 token
**验证**:
- [x] 单元测试覆盖所有方法
- [x] 登录失败场景正确处理(密码错误、账号禁用)
- [x] 密码修改后旧 token 失效
- [x] 错误消息清晰
**依赖**: Task 1.1Token 管理器、Task 2.1AccountStore
---
### Task 3.2: 创建认证 DTO
**文件**: `internal/model/auth_dto.go`
**实现内容**:
- [x] 定义 `LoginRequest` 结构体username, password, device
- [x] 定义 `LoginResponse` 结构体access_token, refresh_token, user, permissions
- [x] 定义 `RefreshTokenRequest` 结构体refresh_token
- [x] 定义 `RefreshTokenResponse` 结构体access_token
- [x] 定义 `ChangePasswordRequest` 结构体old_password, new_password
- [x] 添加 Validator 标签
**验证**:
- [x] 所有字段包含 JSON 标签
- [x] 必填字段包含 validate 标签
- [x] 字段注释清晰(中文)
**依赖**: 无
---
## 阶段 4HTTP 处理层 (3-4 小时)
### Task 4.1: 创建后台认证 Handler
**文件**: `internal/handler/admin/auth.go`
**实现内容**:
- [x] 定义 `AuthHandler` 结构体(注入 `AuthService`
- [x] 实现 `Login()`POST /api/admin/login
- [ ] 解析请求体
- [ ] 验证请求参数
- [ ] 调用 `authService.Login()`
- [ ] 返回统一响应格式
- [x] 实现 `Logout()`POST /api/admin/logout
- [ ] 从 header 提取 token
- [ ] 调用 `authService.Logout()`
- [x] 实现 `RefreshToken()`POST /api/admin/refresh-token
- [ ] 解析请求体
- [ ] 调用 `authService.RefreshToken()`
- [x] 实现 `GetMe()`GET /api/admin/me
- [ ] 从 context 获取 userID
- [ ] 调用 `authService.GetCurrentUser()`
- [x] 实现 `ChangePassword()`PUT /api/admin/password
- [ ] 解析请求体
- [ ] 调用 `authService.ChangePassword()`
**验证**:
- [x] 所有 Handler 返回统一的 JSON 格式
- [x] 错误处理正确(使用 AppError
- [x] 请求参数验证完整
- [x] 响应包含正确的 HTTP 状态码
**依赖**: Task 3.1认证服务、Task 3.2DTO
---
### Task 4.2: 创建 H5 认证 Handler
**文件**: `internal/handler/h5/auth.go`
**实现内容**:
- [x] 复制 `admin/auth.go` 的实现
- [x] 修改路由前缀为 `/api/h5/*`
- [x] 其他逻辑完全相同
**验证**:
- [x] 功能与后台 Handler 一致
- [x] 路由前缀正确
**依赖**: Task 4.1(后台 Handler
---
## 阶段 5路由和中间件配置 (2-3 小时)
### Task 5.1: 配置后台认证中间件
**文件**: `internal/bootstrap/middlewares.go`
**实现内容**:
- [x] 创建 `TokenManager` 实例(注入 Redis、配置
- [x] 创建后台认证中间件(使用 `pkg/middleware/auth.go``Auth()`
- [x] 配置 `TokenValidator` 函数
- [ ] 调用 `tokenManager.ValidateAccessToken()`
- [ ] 检查用户类型(只允许超级管理员、平台用户、代理账号)
- [ ] 返回 `UserContextInfo`
- [x] 配置 `SkipPaths`(登录、刷新 token 接口)
**验证**:
- [x] 中间件正确验证 token
- [x] 用户类型检查正确
- [x] 公开路由不需要认证
**依赖**: Task 1.1Token 管理器)
---
### Task 5.2: 配置 H5 认证中间件
**文件**: `internal/bootstrap/middlewares.go`
**实现内容**:
- [x] 创建 H5 认证中间件(复用 `TokenManager`
- [x] 配置 `TokenValidator` 函数
- [ ] 检查用户类型(只允许代理账号、企业账号)
- [x] 配置 `SkipPaths`
**验证**:
- [x] 用户类型检查正确(与后台不同)
- [x] 公开路由不需要认证
**依赖**: Task 5.1(后台中间件)
---
### Task 5.3: 注册后台认证路由
**文件**: `internal/routes/admin.go`
**实现内容**:
- [x] 创建公开路由组(`/api/admin`
- [ ] POST `/login`:登录
- [ ] POST `/refresh-token`:刷新 token
- [x] 创建受保护路由组(`/api/admin`
- [ ] 应用后台认证中间件
- [ ] POST `/logout`:登出
- [ ] GET `/me`:获取当前用户
- [ ] PUT `/password`:修改密码
**验证**:
- [x] 路由注册正确
- [x] 受保护路由需要 token
- [x] 公开路由无需 token
**依赖**: Task 4.1Handler、Task 5.1(中间件)
---
### Task 5.4: 注册 H5 认证路由
**文件**: `internal/routes/h5.go`(新建)
**实现内容**:
- [x] 创建公开路由组(`/api/h5`
- [x] 创建受保护路由组(`/api/h5`
- [x] 注册与后台相同的路由
**验证**:
- [x] 路由前缀正确(`/api/h5`
- [x] 中间件正确应用
**依赖**: Task 4.2Handler、Task 5.2(中间件)
---
### Task 5.5: 集成到主路由
**文件**: `internal/routes/routes.go`
**实现内容**:
- [x] 调用 `RegisterAdminAuthRoutes()`
- [x] 调用 `RegisterH5AuthRoutes()`
**验证**:
- [x] 所有路由可访问
- [x] 路由优先级正确
**依赖**: Task 5.3、5.4
---
## 阶段 6配置管理 (1 小时)
### Task 6.1: 扩展配置结构
**文件**: `pkg/config/config.go`
**实现内容**:
- [x]`JWTConfig` 中添加 `AccessTokenTTL` 字段(默认 24 小时)
- [x]`JWTConfig` 中添加 `RefreshTokenTTL` 字段(默认 7 天)
- [x]`Validate()` 方法中验证 TTL 范围
**验证**:
- [x] 配置验证正确
- [x] 默认值合理
**依赖**: 无
---
### Task 6.2: 更新配置文件
**文件**: `configs/config.yaml``configs/config.dev.yaml`
**实现内容**:
- [x] 添加 `jwt.access_token_ttl` 配置项
- [x] 添加 `jwt.refresh_token_ttl` 配置项
**验证**:
- [x] 配置文件语法正确
- [x] 开发环境和生产环境配置合理
**依赖**: Task 6.1
---
## 阶段 7测试 (6-8 小时)
### Task 7.1: Token 管理器单元测试
**文件**: `pkg/auth/token_test.go`
**测试用例**:
- [x] 生成 token 对成功
- [x] 验证有效 access token
- [x] 验证有效 refresh token
- [x] 验证过期 token 失败
- [x] 验证无效 token 失败
- [x] 刷新 access token 成功
- [x] 撤销 token 成功
- [x] 撤销用户所有 token 成功
- [x] Redis 连接失败处理
**验证**:
- [x] 覆盖率 ≥ 90%
- [x] 所有测试通过
**依赖**: Task 1.1
---
### Task 7.2: 认证服务单元测试
**文件**: `internal/service/auth/service_test.go`
**测试用例**:
- [x] 登录成功(返回 token 和用户信息)
- [x] 登录失败(密码错误)
- [x] 登录失败(用户名不存在)
- [x] 登录失败(账号禁用)
- [x] 登出成功token 失效)
- [x] 刷新 token 成功
- [x] 刷新 token 失败(无效 refresh token
- [x] 修改密码成功(旧 token 失效)
- [x] 修改密码失败(旧密码错误)
**验证**:
- [x] 覆盖率 ≥ 90%
- [x] Mock `AccountStore``TokenManager`
- [x] 所有测试通过
**依赖**: Task 3.1
---
### Task 7.3: 后台登录接口集成测试
**文件**: `tests/integration/admin_auth_test.go`
**测试用例**:
- [x] 后台登录成功(返回 200 和 token
- [x] 后台登录失败(用户名不存在,返回 401
- [x] 后台登录失败(密码错误,返回 401
- [x] 后台登录失败(账号禁用,返回 403
- [x] 登出成功(返回 200
- [x] 刷新 token 成功(返回 200 和新 token
- [x] 获取当前用户信息成功(返回 200 和用户信息)
- [x] 修改密码成功(返回 200
**验证**:
- [x] 使用真实 PostgreSQL 和 Redistestcontainers
- [x] 所有测试通过
- [x] 响应格式正确
**依赖**: Task 4.1、5.3
---
### Task 7.4: H5 登录接口集成测试
**文件**: `tests/integration/h5_auth_test.go`
**测试用例**:
- [x] H5 登录成功(代理账号)
- [x] H5 登录成功(企业账号)
- [x] H5 登录失败(平台用户无权访问 H5
- [x] 其他测试用例与后台相同
**验证**:
- [x] 用户类型检查正确
- [x] 所有测试通过
**依赖**: Task 4.2、5.4
---
### Task 7.5: 认证中间件集成测试
**文件**: `tests/integration/auth_middleware_test.go`
**测试用例**:
- [x] 有效 token 访问受保护路由(返回 200
- [x] 无效 token 返回 401
- [x] 缺失 token 返回 401
- [x] 过期 token 返回 401
- [x] 后台中间件拒绝 H5 用户类型(返回 403
- [x] H5 中间件拒绝平台用户类型(返回 403
- [x] 公开路由无需 token返回 200
**验证**:
- [x] 中间件行为正确
- [x] 错误码和消息正确
**依赖**: Task 5.1、5.2
---
### Task 7.6: 性能测试
**文件**: `tests/benchmark/auth_bench_test.go`
**测试用例**:
- [x] Token 验证性能(目标:< 5ms
- [x] 登录性能(目标:< 200ms
- [x] 并发登录测试1000 并发)
**验证**:
- [x] 性能达标
- [x] 无内存泄漏
**依赖**: 所有功能完成
---
## 阶段 8文档 (2-3 小时)
### Task 8.1: 创建 API 文档
**文件**: `docs/api/auth.md`
**内容**:
- [x] 登录接口说明(请求、响应、错误码)
- [x] 登出接口说明
- [x] Token 刷新接口说明
- [x] 获取当前用户接口说明
- [x] 修改密码接口说明
- [x] 示例 cURL 请求
- [x] 错误码对照表
**验证**:
- [x] 文档准确完整
- [x] 示例可执行
**依赖**: 所有功能完成
---
### Task 8.2: 创建使用指南
**文件**: `docs/auth-usage-guide.md`
**内容**:
- [x] 如何在新路由中集成认证中间件
- [x] 如何获取当前用户信息
- [x] 如何撤销用户 token
- [x] 常见问题FAQ
- [x] 安全最佳实践
**验证**:
- [x] 文档清晰易懂
- [x] 代码示例正确
**依赖**: 所有功能完成
---
### Task 8.3: 创建架构说明
**文件**: `docs/auth-architecture.md`
**内容**:
- [x] 认证流程图Mermaid
- [x] Token 存储结构说明
- [x] 中间件执行顺序
- [x] 安全机制说明
- [x] 设计决策说明
**验证**:
- [x] 图表清晰
- [x] 说明准确
**依赖**: 所有功能完成
---
### Task 8.4: 更新 README
**文件**: `README.md`
**内容**:
- [x] 在"核心功能"章节添加"B 端认证系统"
- [x] 在"快速开始"章节添加登录示例
- [x] 更新项目结构说明
**验证**:
- [x] 更新准确
- [x] 链接有效
**依赖**: Task 8.1、8.2、8.3
---
## 阶段 9验收和发布 (1 小时)
### Task 9.1: 完整性检查
- [x] 所有测试通过(`go test ./...`
- [x] 测试覆盖率达标(`go test -cover ./...`
- [x] LSP 诊断无错误(`lsp_diagnostics`
- [x] 代码格式化(`gofmt`
- [x] 所有 TODO 完成
**验证**:
- [x] CI/CD 构建通过
- [x] 无遗留问题
---
### Task 9.2: 代码审查
- [x] 提交 PR
- [x] 代码审查通过
- [x] 修复审查意见
**验证**:
- [x] PR 获得批准
---
### Task 9.3: 部署验证
- [x] 在测试环境部署
- [x] 手动测试所有接口
- [x] 验证性能指标
- [x] 验证安全性
**验证**:
- [x] 所有验收标准达成
- [x] 用户满意
---
## 总结
**总工作量估算**: 22-31 小时3-5 个工作日)
**关键路径**:
1. Task 1.1Token 管理器)→ Task 3.1(认证服务)→ Task 4.1Handler→ Task 5.3(路由)
2. Task 7.1-7.6(测试)必须在功能完成后执行
3. Task 8.1-8.4(文档)可与测试并行
**并行任务**:
- Task 1.2、1.3 可与 Task 1.1 并行
- Task 3.2 可与 Task 3.1 并行
- Task 4.2 可在 Task 4.1 完成后立即开始
- Task 5.2、5.4 可在 Task 5.1、5.3 完成后立即开始
- Task 8.1-8.4 可并行执行
**风险点**:
- Redis 集成测试可能需要额外调试时间
- 中间件配置可能与现有路由冲突
- 性能测试可能需要优化
---
**任务状态**: 待执行
**创建时间**: 2026-01-15
**最后更新**: 2026-01-15