refactor(account): 统一账号管理API、完善权限检查和操作审计
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 6m17s
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 6m17s
- 合并 customer_account 和 shop_account 路由到统一的 account 接口 - 新增统一认证接口 (auth handler) - 实现越权防护中间件和权限检查工具函数 - 新增操作审计日志模型和服务 - 更新数据库迁移 (版本 39: account_operation_log 表) - 补充集成测试覆盖权限检查和审计日志场景
This commit is contained in:
143
openspec/specs/account-management/spec.md
Normal file
143
openspec/specs/account-management/spec.md
Normal file
@@ -0,0 +1,143 @@
|
||||
# 账号管理接口规格
|
||||
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: 统一账号管理路由结构
|
||||
系统 SHALL 提供统一的账号管理路由,按账号类型分组。
|
||||
|
||||
#### Scenario: 平台账号管理路由
|
||||
- **WHEN** 访问 /api/admin/accounts/platform/*
|
||||
- **THEN** 提供平台账号的 CRUD + 角色管理功能
|
||||
|
||||
#### Scenario: 代理账号管理路由
|
||||
- **WHEN** 访问 /api/admin/accounts/shop/*
|
||||
- **THEN** 提供代理账号的 CRUD + 角色管理功能
|
||||
|
||||
#### Scenario: 企业账号管理路由
|
||||
- **WHEN** 访问 /api/admin/accounts/enterprise/*
|
||||
- **THEN** 提供企业账号的 CRUD + 角色管理功能
|
||||
|
||||
### Requirement: 所有账号类型支持完整的CRUD操作
|
||||
系统 SHALL 为所有账号类型提供一致的 CRUD 功能。
|
||||
|
||||
#### Scenario: 创建账号
|
||||
- **WHEN** POST /api/admin/accounts/{type}
|
||||
- **THEN** 验证权限,创建账号,返回账号信息
|
||||
|
||||
#### Scenario: 查询账号列表
|
||||
- **WHEN** GET /api/admin/accounts/{type}
|
||||
- **THEN** 应用数据权限过滤,返回分页列表
|
||||
|
||||
#### Scenario: 查询账号详情
|
||||
- **WHEN** GET /api/admin/accounts/{type}/:id
|
||||
- **THEN** 验证权限,返回账号详情
|
||||
|
||||
#### Scenario: 更新账号
|
||||
- **WHEN** PUT /api/admin/accounts/{type}/:id
|
||||
- **THEN** 验证权限,更新账号,返回更新后信息
|
||||
|
||||
#### Scenario: 删除账号
|
||||
- **WHEN** DELETE /api/admin/accounts/{type}/:id
|
||||
- **THEN** 验证权限,软删除账号,返回成功
|
||||
|
||||
### Requirement: 所有账号类型支持密码和状态管理
|
||||
系统 SHALL 为所有账号类型提供统一的密码和状态管理功能。
|
||||
|
||||
#### Scenario: 修改账号密码
|
||||
- **WHEN** PUT /api/admin/accounts/{type}/:id/password
|
||||
- **THEN** 验证权限,更新密码(bcrypt哈希),返回成功
|
||||
|
||||
#### Scenario: 启用账号
|
||||
- **WHEN** PUT /api/admin/accounts/{type}/:id/status,status=1
|
||||
- **THEN** 验证权限,更新状态为启用,返回成功
|
||||
|
||||
#### Scenario: 禁用账号
|
||||
- **WHEN** PUT /api/admin/accounts/{type}/:id/status,status=0
|
||||
- **THEN** 验证权限,更新状态为禁用,返回成功
|
||||
|
||||
### Requirement: 所有账号类型支持角色管理
|
||||
系统 SHALL 为所有账号类型提供统一的角色管理功能。
|
||||
|
||||
#### Scenario: 分配角色
|
||||
- **WHEN** POST /api/admin/accounts/{type}/:id/roles,body: {role_ids: [1,2]}
|
||||
- **THEN** 验证权限,分配角色,返回成功
|
||||
|
||||
#### Scenario: 查询账号角色
|
||||
- **WHEN** GET /api/admin/accounts/{type}/:id/roles
|
||||
- **THEN** 验证权限,返回账号的所有角色列表
|
||||
|
||||
#### Scenario: 移除角色
|
||||
- **WHEN** DELETE /api/admin/accounts/{type}/:id/roles/:role_id
|
||||
- **THEN** 验证权限,软删除角色关联,返回成功
|
||||
|
||||
#### Scenario: 清空所有角色
|
||||
- **WHEN** POST /api/admin/accounts/{type}/:id/roles,body: {role_ids: []}
|
||||
- **THEN** 验证权限,删除所有角色关联,返回成功
|
||||
|
||||
### Requirement: 删除旧路由避免冲突
|
||||
系统 SHALL 删除旧的账号管理路由,避免与新路由冲突。
|
||||
|
||||
#### Scenario: 旧平台账号路由404
|
||||
- **WHEN** 访问 POST /api/admin/platform-accounts
|
||||
- **THEN** 返回 404 Not Found
|
||||
|
||||
#### Scenario: 旧代理账号路由404
|
||||
- **WHEN** 访问 GET /api/admin/shop-accounts
|
||||
- **THEN** 返回 404 Not Found
|
||||
|
||||
#### Scenario: 旧企业账号路由404
|
||||
- **WHEN** 访问 POST /api/admin/customer-accounts
|
||||
- **THEN** 返回 404 Not Found
|
||||
|
||||
### Requirement: 响应格式保持一致
|
||||
系统 SHALL 为所有账号类型返回一致的响应格式。
|
||||
|
||||
#### Scenario: 创建响应包含完整账号信息
|
||||
- **WHEN** 创建账号成功
|
||||
- **THEN** 返回账号 ID、用户名、手机号、用户类型、状态、创建时间
|
||||
|
||||
#### Scenario: 列表响应包含分页信息
|
||||
- **WHEN** 查询账号列表
|
||||
- **THEN** 返回 {items, total, page, size}
|
||||
|
||||
#### Scenario: 错误响应使用统一格式
|
||||
- **WHEN** 操作失败
|
||||
- **THEN** 返回 {code, message, timestamp}
|
||||
|
||||
### Requirement: 支持按条件筛选账号列表
|
||||
系统 SHALL 支持按多个条件筛选账号列表。
|
||||
|
||||
#### Scenario: 按用户名筛选
|
||||
- **WHEN** GET /api/admin/accounts/{type}?username=张三
|
||||
- **THEN** 返回用户名包含"张三"的账号列表
|
||||
|
||||
#### Scenario: 按手机号筛选
|
||||
- **WHEN** GET /api/admin/accounts/{type}?phone=138
|
||||
- **THEN** 返回手机号包含"138"的账号列表
|
||||
|
||||
#### Scenario: 按状态筛选
|
||||
- **WHEN** GET /api/admin/accounts/{type}?status=1
|
||||
- **THEN** 返回状态为启用的账号列表
|
||||
|
||||
#### Scenario: 按店铺ID筛选(代理账号)
|
||||
- **WHEN** GET /api/admin/accounts/shop?shop_id=100
|
||||
- **THEN** 返回 shop_id=100 的代理账号列表(需权限验证)
|
||||
|
||||
#### Scenario: 按企业ID筛选(企业账号)
|
||||
- **WHEN** GET /api/admin/accounts/enterprise?enterprise_id=50
|
||||
- **THEN** 返回 enterprise_id=50 的企业账号列表(需权限验证)
|
||||
|
||||
### Requirement: 统一Service层实现消除重复
|
||||
系统 SHALL 使用单一 AccountService 处理所有账号类型,消除代码重复。
|
||||
|
||||
#### Scenario: AccountService处理所有账号类型
|
||||
- **WHEN** 调用 AccountService.Create(ctx, req)
|
||||
- **THEN** 根据 req.UserType 创建不同类型账号(平台、代理、企业)
|
||||
|
||||
#### Scenario: 删除ShopAccountService
|
||||
- **WHEN** 系统重构完成
|
||||
- **THEN** ShopAccountService 及相关文件应被删除
|
||||
|
||||
#### Scenario: 删除CustomerAccountService
|
||||
- **WHEN** 系统重构完成
|
||||
- **THEN** CustomerAccountService 及相关文件应被删除
|
||||
105
openspec/specs/account-operation-audit/spec.md
Normal file
105
openspec/specs/account-operation-audit/spec.md
Normal file
@@ -0,0 +1,105 @@
|
||||
# 账号操作审计日志规格
|
||||
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: 记录所有账号管理操作
|
||||
系统 SHALL 记录所有账号管理操作,包括创建、更新、删除、角色分配和移除。
|
||||
|
||||
#### Scenario: 创建账号时记录审计日志
|
||||
- **WHEN** 用户创建账号成功
|
||||
- **THEN** 系统应异步写入审计日志,包含操作人、目标账号、操作类型(create)、变更数据(after_data)
|
||||
|
||||
#### Scenario: 更新账号时记录变更前后数据
|
||||
- **WHEN** 用户更新账号信息(用户名、手机号、状态等)
|
||||
- **THEN** 系统应记录 before_data 和 after_data,包含所有变更字段
|
||||
|
||||
#### Scenario: 删除账号时记录审计日志
|
||||
- **WHEN** 用户软删除账号
|
||||
- **THEN** 系统应记录删除操作,包含被删除账号的完整信息(before_data)
|
||||
|
||||
#### Scenario: 分配角色时记录审计日志
|
||||
- **WHEN** 用户为账号分配角色
|
||||
- **THEN** 系统应记录 operation_type=assign_roles,after_data 包含分配的角色 ID 列表
|
||||
|
||||
#### Scenario: 移除角色时记录审计日志
|
||||
- **WHEN** 用户移除账号的角色
|
||||
- **THEN** 系统应记录 operation_type=remove_role,包含被移除的角色 ID
|
||||
|
||||
### Requirement: 审计日志包含完整的操作上下文
|
||||
系统 SHALL 在审计日志中记录操作人、目标对象、变更内容和请求上下文。
|
||||
|
||||
#### Scenario: 记录操作人信息
|
||||
- **WHEN** 记录审计日志
|
||||
- **THEN** 日志应包含 operator_id、operator_type、operator_name
|
||||
|
||||
#### Scenario: 记录目标账号信息
|
||||
- **WHEN** 记录审计日志
|
||||
- **THEN** 日志应包含 target_account_id、target_username、target_user_type
|
||||
|
||||
#### Scenario: 记录变更数据(JSON格式)
|
||||
- **WHEN** 记录更新操作
|
||||
- **THEN** before_data 和 after_data 应为 JSONB 格式,包含完整的字段信息
|
||||
|
||||
#### Scenario: 记录请求上下文
|
||||
- **WHEN** 记录审计日志
|
||||
- **THEN** 日志应包含 request_id、ip_address、user_agent,可关联访问日志
|
||||
|
||||
### Requirement: 异步写入不阻塞业务流程
|
||||
系统 SHALL 使用 Goroutine 异步写入审计日志,确保业务操作不受审计日志性能影响。
|
||||
|
||||
#### Scenario: 异步写入审计日志
|
||||
- **WHEN** AccountService.Create 创建账号成功
|
||||
- **THEN** 主流程立即返回,审计日志在独立 Goroutine 中异步写入
|
||||
|
||||
#### Scenario: 写入失败只记录错误日志
|
||||
- **WHEN** 审计日志写入数据库失败
|
||||
- **THEN** 记录 Error 级别日志,包含完整审计信息,但不影响业务操作结果
|
||||
|
||||
#### Scenario: 业务响应时间不受影响
|
||||
- **WHEN** 执行账号创建操作
|
||||
- **THEN** API 响应时间不应因审计日志写入而增加(< 1ms)
|
||||
|
||||
### Requirement: 操作描述使用中文
|
||||
系统 SHALL 使用中文描述审计日志的操作类型和内容。
|
||||
|
||||
#### Scenario: 创建操作描述
|
||||
- **WHEN** 记录创建账号操作
|
||||
- **THEN** operation_desc 应为 "创建账号: {username}"
|
||||
|
||||
#### Scenario: 更新操作描述
|
||||
- **WHEN** 记录更新账号操作
|
||||
- **THEN** operation_desc 应为 "更新账号: {username}"
|
||||
|
||||
#### Scenario: 删除操作描述
|
||||
- **WHEN** 记录删除账号操作
|
||||
- **THEN** operation_desc 应为 "删除账号: {username}"
|
||||
|
||||
#### Scenario: 分配角色操作描述
|
||||
- **WHEN** 记录分配角色操作
|
||||
- **THEN** operation_desc 应为 "为账号 {username} 分配角色"
|
||||
|
||||
### Requirement: 支持按多维度查询审计日志
|
||||
系统 SHALL 提供索引支持按操作人、目标账号、时间快速查询审计日志。
|
||||
|
||||
#### Scenario: 按操作人查询日志
|
||||
- **WHEN** 查询特定操作人的所有操作记录
|
||||
- **THEN** 使用 idx_account_log_operator 索引,查询时间 < 50ms
|
||||
|
||||
#### Scenario: 按目标账号查询日志
|
||||
- **WHEN** 查询特定账号的所有操作记录
|
||||
- **THEN** 使用 idx_account_log_target 索引,查询时间 < 50ms
|
||||
|
||||
#### Scenario: 按时间范围查询日志
|
||||
- **WHEN** 查询最近7天的操作记录
|
||||
- **THEN** 使用 idx_account_log_created 索引,支持倒序分页
|
||||
|
||||
### Requirement: 关联访问日志追溯完整请求链路
|
||||
系统 SHALL 通过 request_id 关联审计日志和访问日志,支持完整链路追溯。
|
||||
|
||||
#### Scenario: 通过request_id关联日志
|
||||
- **WHEN** 审计日志中记录 request_id="req-12345"
|
||||
- **THEN** 可以在 access.log 中查询到对应的 HTTP 请求日志
|
||||
|
||||
#### Scenario: 追溯完整请求链路
|
||||
- **WHEN** 运维人员调查某个账号创建操作
|
||||
- **THEN** 通过 request_id 可以查询到:请求参数、权限检查、数据库操作、响应结果
|
||||
127
openspec/specs/account-permission-check/spec.md
Normal file
127
openspec/specs/account-permission-check/spec.md
Normal file
@@ -0,0 +1,127 @@
|
||||
# 账号管理权限检查规格
|
||||
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: 三层越权防护架构
|
||||
系统 SHALL 实现三层越权防护机制,确保账号管理操作的安全性。
|
||||
|
||||
#### Scenario: 路由层中间件拦截企业账号
|
||||
- **WHEN** 企业账号(user_type=4)访问账号管理接口(/api/admin/accounts/*)
|
||||
- **THEN** 中间件应返回 403 错误:"无权限访问账号管理功能"
|
||||
|
||||
#### Scenario: Service层权限检查成功
|
||||
- **WHEN** 代理账号创建自己店铺的账号
|
||||
- **THEN** CanManageShop 检查应通过,账号创建成功
|
||||
|
||||
#### Scenario: GORM层自动过滤生效
|
||||
- **WHEN** 代理账号查询账号列表
|
||||
- **THEN** GORM Callback 应自动添加 `shop_id IN (当前店铺+下级店铺)` 过滤条件
|
||||
|
||||
### Requirement: 代理账号只能管理自己店铺及下级店铺的账号
|
||||
系统 SHALL 验证代理账号对目标店铺的管理权限,禁止跨店铺越权操作。
|
||||
|
||||
#### Scenario: 代理创建自己店铺的账号成功
|
||||
- **WHEN** 代理账号(shop_id=100)创建 shop_id=100 的账号
|
||||
- **THEN** 权限检查通过,账号创建成功
|
||||
|
||||
#### Scenario: 代理创建下级店铺的账号成功
|
||||
- **WHEN** 代理账号(shop_id=100,下级:101,102)创建 shop_id=101 的账号
|
||||
- **THEN** GetSubordinateShopIDs 返回 [100,101,102],权限检查通过
|
||||
|
||||
#### Scenario: 代理创建其他店铺的账号失败
|
||||
- **WHEN** 代理账号(shop_id=100)创建 shop_id=200 的账号
|
||||
- **THEN** CanManageShop 返回错误:"无权限管理该店铺的账号",创建失败
|
||||
|
||||
#### Scenario: 代理创建平台账号失败
|
||||
- **WHEN** 代理账号尝试创建 user_type=2 的平台账号
|
||||
- **THEN** Service 层检查返回错误:"无权限创建平台账号",创建失败
|
||||
|
||||
### Requirement: 平台账号和超级管理员可以管理所有账号
|
||||
系统 SHALL 允许平台账号和超级管理员跳过所有权限检查,管理所有账号。
|
||||
|
||||
#### Scenario: 平台账号创建任意类型账号
|
||||
- **WHEN** 平台账号(user_type=2)创建代理账号(user_type=3, shop_id=100)
|
||||
- **THEN** 权限检查跳过,账号创建成功
|
||||
|
||||
#### Scenario: 超级管理员创建任意类型账号
|
||||
- **WHEN** 超级管理员(user_type=1)创建任意类型账号
|
||||
- **THEN** 权限检查跳过,账号创建成功
|
||||
|
||||
#### Scenario: 平台账号查询所有账号
|
||||
- **WHEN** 平台账号调用账号列表接口
|
||||
- **THEN** GORM Callback 跳过过滤,返回所有账号
|
||||
|
||||
### Requirement: 企业账号禁止访问账号管理接口
|
||||
系统 SHALL 禁止企业账号访问所有账号管理接口。
|
||||
|
||||
#### Scenario: 企业账号创建账号失败(路由层拦截)
|
||||
- **WHEN** 企业账号(user_type=4)调用 POST /api/admin/accounts/enterprise
|
||||
- **THEN** 路由层中间件返回 403 错误:"无权限访问账号管理功能"
|
||||
|
||||
#### Scenario: 企业账号更新账号失败(Service层拦截)
|
||||
- **WHEN** 企业账号绕过路由层,直接调用 AccountService.Update
|
||||
- **THEN** Service 层返回 403 错误:"企业账号不允许更新账号"
|
||||
|
||||
### Requirement: 统一错误返回防止信息泄露
|
||||
系统 SHALL 在越权访问时统一返回模糊错误消息,防止攻击者判断资源是否存在。
|
||||
|
||||
#### Scenario: 查询不存在的账号返回模糊错误
|
||||
- **WHEN** 用户查询不存在的账号 ID
|
||||
- **THEN** 返回 403 错误:"无权限操作该资源或资源不存在"
|
||||
|
||||
#### Scenario: 查询越权的账号返回相同错误
|
||||
- **WHEN** 代理账号(shop_id=100)查询 shop_id=200 的账号
|
||||
- **THEN** 返回 403 错误:"无权限操作该资源或资源不存在"(与不存在的错误消息相同)
|
||||
|
||||
### Requirement: CanManageShop 权限检查函数
|
||||
系统 SHALL 提供 CanManageShop 函数验证用户对目标店铺的管理权限。
|
||||
|
||||
#### Scenario: 验证代理对自己店铺的权限
|
||||
- **WHEN** 调用 CanManageShop(ctx, 100, shopStore) 且当前用户 shop_id=100
|
||||
- **THEN** 返回 nil(有权限)
|
||||
|
||||
#### Scenario: 验证代理对下级店铺的权限
|
||||
- **WHEN** 调用 CanManageShop(ctx, 101, shopStore) 且当前用户 shop_id=100,下级包含 101
|
||||
- **THEN** GetSubordinateShopIDs 返回 [100,101,102],返回 nil(有权限)
|
||||
|
||||
#### Scenario: 验证代理对其他店铺的权限失败
|
||||
- **WHEN** 调用 CanManageShop(ctx, 200, shopStore) 且当前用户 shop_id=100
|
||||
- **THEN** 返回错误:"无权限管理该店铺的账号"
|
||||
|
||||
#### Scenario: 验证平台账号自动通过
|
||||
- **WHEN** 调用 CanManageShop(ctx, 200, shopStore) 且当前用户 user_type=2(平台)
|
||||
- **THEN** 不调用 GetSubordinateShopIDs,直接返回 nil(有权限)
|
||||
|
||||
### Requirement: CanManageEnterprise 权限检查函数
|
||||
系统 SHALL 提供 CanManageEnterprise 函数验证用户对目标企业的管理权限。
|
||||
|
||||
#### Scenario: 验证平台账号管理任意企业
|
||||
- **WHEN** 调用 CanManageEnterprise(ctx, 50, enterpriseStore, shopStore) 且当前用户 user_type=2
|
||||
- **THEN** 返回 nil(有权限)
|
||||
|
||||
#### Scenario: 验证代理对归属企业的权限
|
||||
- **WHEN** 调用 CanManageEnterprise(ctx, 50, enterpriseStore, shopStore) 且企业 owner_shop_id=100,当前用户 shop_id=100
|
||||
- **THEN** 返回 nil(有权限)
|
||||
|
||||
#### Scenario: 验证代理对下级店铺企业的权限
|
||||
- **WHEN** 调用 CanManageEnterprise(ctx, 50, enterpriseStore, shopStore) 且企业 owner_shop_id=101,当前用户 shop_id=100,下级包含 101
|
||||
- **THEN** 返回 nil(有权限)
|
||||
|
||||
#### Scenario: 验证代理对其他店铺企业的权限失败
|
||||
- **WHEN** 调用 CanManageEnterprise(ctx, 50, enterpriseStore, shopStore) 且企业 owner_shop_id=200,当前用户 shop_id=100
|
||||
- **THEN** 返回错误:"无权限管理该企业的账号"
|
||||
|
||||
### Requirement: 权限检查性能优化
|
||||
系统 SHALL 使用 Redis 缓存优化权限检查性能,确保 API 响应时间 < 200ms。
|
||||
|
||||
#### Scenario: GetSubordinateShopIDs 命中缓存
|
||||
- **WHEN** 调用 GetSubordinateShopIDs(ctx, 100) 且缓存存在
|
||||
- **THEN** 从 Redis 读取缓存,不查询数据库,耗时 < 5ms
|
||||
|
||||
#### Scenario: GetSubordinateShopIDs 缓存未命中
|
||||
- **WHEN** 调用 GetSubordinateShopIDs(ctx, 100) 且缓存不存在
|
||||
- **THEN** 递归查询数据库,写入 Redis 缓存(30分钟),返回结果
|
||||
|
||||
#### Scenario: 权限检查总耗时 < 10ms
|
||||
- **WHEN** 执行完整权限检查(包含 GetSubordinateShopIDs)
|
||||
- **THEN** 总耗时 < 10ms(缓存命中时 < 5ms)
|
||||
86
openspec/specs/unified-auth-api/spec.md
Normal file
86
openspec/specs/unified-auth-api/spec.md
Normal file
@@ -0,0 +1,86 @@
|
||||
# 统一认证接口规格
|
||||
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: 合并后台和H5认证接口
|
||||
系统 SHALL 提供统一认证接口 /api/auth/*,支持后台和 H5 两种场景的认证。
|
||||
|
||||
#### Scenario: 后台用户登录
|
||||
- **WHEN** 用户调用 POST /api/auth/login,user_type IN (1,2,3,4)
|
||||
- **THEN** 验证用户名+密码,返回 Access Token + Refresh Token
|
||||
|
||||
#### Scenario: H5用户登录
|
||||
- **WHEN** H5 用户调用 POST /api/auth/login,user_type IN (3,4)
|
||||
- **THEN** 验证用户名+密码,返回 Access Token + Refresh Token
|
||||
|
||||
#### Scenario: 登出统一接口
|
||||
- **WHEN** 用户调用 POST /api/auth/logout
|
||||
- **THEN** 删除 Redis 中的 Token,返回成功
|
||||
|
||||
#### Scenario: 刷新Token统一接口
|
||||
- **WHEN** 用户调用 POST /api/auth/refresh-token
|
||||
- **THEN** 验证 Refresh Token,返回新的 Access Token
|
||||
|
||||
#### Scenario: 获取用户信息统一接口
|
||||
- **WHEN** 用户调用 GET /api/auth/me
|
||||
- **THEN** 返回当前用户信息,包含 menus 和 buttons
|
||||
|
||||
### Requirement: 保留个人客户认证接口
|
||||
系统 SHALL 保持个人客户认证接口 /api/c/v1/* 独立,不与后台/H5认证合并。
|
||||
|
||||
#### Scenario: 个人客户微信授权登录
|
||||
- **WHEN** 个人客户调用 POST /api/c/v1/wechat/auth
|
||||
- **THEN** 使用微信 OAuth 流程,返回 JWT Token
|
||||
|
||||
#### Scenario: 个人客户手机号登录
|
||||
- **WHEN** 个人客户调用 POST /api/c/v1/login
|
||||
- **THEN** 验证手机号+验证码,返回 JWT Token
|
||||
|
||||
#### Scenario: 个人客户获取资料
|
||||
- **WHEN** 个人客户调用 GET /api/c/v1/profile
|
||||
- **THEN** 返回个人客户资料(独立数据结构)
|
||||
|
||||
### Requirement: 删除旧认证接口路由
|
||||
系统 SHALL 删除 /api/admin/login、/api/h5/login 等旧路由,统一为 /api/auth/*。
|
||||
|
||||
#### Scenario: 旧后台登录接口404
|
||||
- **WHEN** 用户调用 POST /api/admin/login
|
||||
- **THEN** 返回 404 Not Found
|
||||
|
||||
#### Scenario: 旧H5登录接口404
|
||||
- **WHEN** 用户调用 POST /api/h5/login
|
||||
- **THEN** 返回 404 Not Found
|
||||
|
||||
#### Scenario: 新统一接口正常工作
|
||||
- **WHEN** 用户调用 POST /api/auth/login
|
||||
- **THEN** 正常认证,返回 200 OK
|
||||
|
||||
### Requirement: 认证逻辑保持不变
|
||||
系统 SHALL 保持认证逻辑不变,只修改路由路径。
|
||||
|
||||
#### Scenario: Token生成逻辑不变
|
||||
- **WHEN** 用户登录成功
|
||||
- **THEN** 生成相同格式的 Access Token(24小时)和 Refresh Token(7天)
|
||||
|
||||
#### Scenario: Token存储在Redis
|
||||
- **WHEN** 生成 Token
|
||||
- **THEN** 存储在 Redis,Key 格式为 "auth:token:{token}"
|
||||
|
||||
#### Scenario: 用户类型过滤不变
|
||||
- **WHEN** 登录请求中包含 user_type
|
||||
- **THEN** 验证用户类型是否与账号类型匹配
|
||||
|
||||
### Requirement: 响应格式保持兼容
|
||||
系统 SHALL 保持登录响应格式兼容,包含 menus 和 buttons。
|
||||
|
||||
#### Scenario: 登录响应包含菜单
|
||||
- **WHEN** 用户登录成功
|
||||
- **THEN** 响应应包含 menus(菜单树结构)
|
||||
|
||||
#### Scenario: 登录响应包含按钮权限
|
||||
- **WHEN** 用户登录成功
|
||||
- **THEN** 响应应包含 buttons(按钮权限列表)
|
||||
|
||||
#### Scenario: 响应格式不变
|
||||
- **WHEN** 用户登录成功
|
||||
- **THEN** 响应格式应与旧接口完全一致,前端无需修改解析逻辑
|
||||
Reference in New Issue
Block a user