refactor(account): 统一账号管理API、完善权限检查和操作审计
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:
2026-02-02 17:23:20 +08:00
parent 5851cc6403
commit 80f560df33
58 changed files with 10743 additions and 4915 deletions

View File

@@ -0,0 +1,310 @@
# 账号管理接口迁移指南
## 概述
本次重构统一了账号管理和认证接口架构,简化了路由结构,前端需要更新所有相关接口调用。
## Breaking Changes
### 1. 账号管理接口路由变更
所有账号管理接口统一为 `/api/admin/accounts/*` 结构,**不再按账号类型区分路由**
| 旧路由前缀 | 新路由前缀 | 说明 |
|-----------|-----------|------|
| `/api/admin/platform-accounts` | `/api/admin/accounts` | 平台账号 |
| `/api/admin/shop-accounts` | `/api/admin/accounts` | 代理账号 |
| `/api/admin/customer-accounts` | `/api/admin/accounts` | 企业账号(改名) |
**重要变更**
- ✅ 所有账号类型共享同一套路由
- ✅ 账号类型通过**请求体的 `user_type` 字段**区分2=平台3=代理4=企业)
-`customer-accounts` 改名为 `enterprise`(命名更准确)
#### 完整路由映射10个接口
| 功能 | HTTP 方法 | 旧路径示例(平台账号) | 新路径(统一) |
|------|-----------|---------------------|-------------|
| 创建账号 | POST | `/api/admin/platform-accounts` | `/api/admin/accounts` |
| 查询列表 | GET | `/api/admin/platform-accounts` | `/api/admin/accounts` |
| 获取详情 | GET | `/api/admin/platform-accounts/:id` | `/api/admin/accounts/:id` |
| 更新账号 | PUT | `/api/admin/platform-accounts/:id` | `/api/admin/accounts/:id` |
| 删除账号 | DELETE | `/api/admin/platform-accounts/:id` | `/api/admin/accounts/:id` |
| 修改密码 | PUT | `/api/admin/platform-accounts/:id/password` | `/api/admin/accounts/:id/password` |
| 修改状态 | PUT | `/api/admin/platform-accounts/:id/status` | `/api/admin/accounts/:id/status` |
| 分配角色 | POST | `/api/admin/platform-accounts/:id/roles` | `/api/admin/accounts/:id/roles` |
| 获取角色 | GET | `/api/admin/platform-accounts/:id/roles` | `/api/admin/accounts/:id/roles` |
| 移除角色 | DELETE | `/api/admin/platform-accounts/:id/roles/:role_id` | `/api/admin/accounts/:account_id/roles/:role_id` |
**⚠️ 特别注意**:移除角色接口的路径参数从 `:id` 改为 `:account_id`
### 2. 认证接口路由变更
后台和 H5 认证接口合并为统一的 `/api/auth/*`
| 功能 | 后台旧路由 | H5 旧路由 | 新路由(统一) |
|------|-----------|----------|-------------|
| 登录 | `/api/admin/login` | `/api/h5/login` | `/api/auth/login` |
| 登出 | `/api/admin/logout` | `/api/h5/logout` | `/api/auth/logout` |
| 刷新Token | `/api/admin/refresh-token` | `/api/h5/refresh-token` | `/api/auth/refresh-token` |
| 获取用户信息 | `/api/admin/me` | `/api/h5/me` | `/api/auth/me` |
| 修改密码 | `/api/admin/password` | `/api/h5/password` | `/api/auth/password` |
**个人客户认证不受影响**`/api/c/v1/*` 保持不变
## 数据结构变更
### 请求体变更:账号类型通过 user_type 字段区分
创建账号时,必须在请求体中指定 `user_type`
```json
{
"username": "test_user",
"phone": "13800000001",
"password": "Password123",
"user_type": 2, // 必填2=平台用户3=代理账号4=企业账号
"shop_id": 10, // 代理账号必填
"enterprise_id": 5 // 企业账号必填
}
```
查询账号列表时,可通过 `user_type` 参数筛选:
```
GET /api/admin/accounts?user_type=3 // 查询代理账号
GET /api/admin/accounts // 查询所有账号
```
### 响应体无变化
所有接口的响应体结构保持不变。
## 迁移步骤
### 第一步:批量替换路由
使用编辑器全局搜索替换:
```
# 账号管理路由(所有账号类型统一)
/api/admin/platform-accounts → /api/admin/accounts
/api/admin/shop-accounts → /api/admin/accounts
/api/admin/customer-accounts → /api/admin/accounts
# 认证路由(后台)
/api/admin/login → /api/auth/login
/api/admin/logout → /api/auth/logout
/api/admin/refresh-token → /api/auth/refresh-token
/api/admin/me → /api/auth/me
/api/admin/password → /api/auth/password
# 认证路由H5
/api/h5/login → /api/auth/login
/api/h5/logout → /api/auth/logout
/api/h5/refresh-token → /api/auth/refresh-token
/api/h5/me → /api/auth/me
/api/h5/password → /api/auth/password
```
### 第二步:更新账号创建逻辑
**旧代码**(根据路由区分账号类型):
```javascript
// ❌ 错误:通过不同路由创建不同类型账号
const createPlatformAccount = (data) => axios.post('/api/admin/platform-accounts', data);
const createShopAccount = (data) => axios.post('/api/admin/shop-accounts', data);
const createEnterpriseAccount = (data) => axios.post('/api/admin/customer-accounts', data);
```
**新代码**(通过 user_type 区分账号类型):
```javascript
// ✅ 正确:统一路由,通过 user_type 区分
const createAccount = (data) => axios.post('/api/admin/accounts', {
...data,
user_type: data.user_type, // 2=平台, 3=代理, 4=企业
});
// 使用示例
createAccount({ username: 'test', user_type: 2, ...otherData }); // 创建平台账号
createAccount({ username: 'agent1', user_type: 3, shop_id: 10, ...otherData }); // 创建代理账号
createAccount({ username: 'ent1', user_type: 4, enterprise_id: 5, ...otherData }); // 创建企业账号
```
### 第三步:更新账号查询逻辑
**旧代码**(分别查询不同类型账号):
```javascript
// ❌ 错误:三个不同的查询接口
const getPlatformAccounts = (params) => axios.get('/api/admin/platform-accounts', { params });
const getShopAccounts = (params) => axios.get('/api/admin/shop-accounts', { params });
const getEnterpriseAccounts = (params) => axios.get('/api/admin/customer-accounts', { params });
```
**新代码**(统一查询,可选筛选):
```javascript
// ✅ 正确:统一查询接口,通过 user_type 筛选
const getAccounts = (params) => axios.get('/api/admin/accounts', { params });
// 使用示例
getAccounts({ user_type: 2 }); // 查询平台账号
getAccounts({ user_type: 3 }); // 查询代理账号
getAccounts({ user_type: 4 }); // 查询企业账号
getAccounts({}); // 查询所有账号
```
### 第四步:更新类型定义(如果使用 TypeScript
```typescript
// 旧类型
type AccountType = 'platform' | 'shop' | 'customer';
// 新类型
type AccountType = 'platform' | 'shop' | 'enterprise'; // customer 改名为 enterprise
// 新增:账号类型值枚举
enum UserType {
Platform = 2, // 平台用户
Agent = 3, // 代理账号
Enterprise = 4, // 企业账号
}
```
### 第五步:测试验证
1. **后台系统**
- 登录/登出功能
- 平台账号 CRUD
- 代理账号 CRUD
- 企业账号 CRUD
- 角色管理功能
2. **H5 系统**
- 登录/登出功能
- 代理账号自助操作
- 企业账号自助操作
3. **个人客户端**
- 确认认证接口不受影响
## 快速迁移示例
### Vue/React 项目
```javascript
// 旧配置
const API = {
platformAccounts: '/api/admin/platform-accounts',
shopAccounts: '/api/admin/shop-accounts',
customerAccounts: '/api/admin/customer-accounts',
adminLogin: '/api/admin/login',
h5Login: '/api/h5/login',
}
// 新配置
const API = {
accounts: '/api/admin/accounts', // 统一账号管理接口
login: '/api/auth/login', // 统一认证接口
logout: '/api/auth/logout',
refreshToken: '/api/auth/refresh-token',
me: '/api/auth/me',
updatePassword: '/api/auth/password',
}
// 使用示例
const accountAPI = {
// 创建账号(根据 user_type 区分类型)
create: (data) => axios.post(API.accounts, data),
// 查询账号列表(可选筛选 user_type
list: (params) => axios.get(API.accounts, { params }),
// 获取详情
get: (id) => axios.get(`${API.accounts}/${id}`),
// 更新账号
update: (id, data) => axios.put(`${API.accounts}/${id}`, data),
// 删除账号
delete: (id) => axios.delete(`${API.accounts}/${id}`),
// 其他操作...
};
```
## 常见问题
### Q1为什么要做这次重构
**A**:解决以下问题:
1. 接口重复(三种账号类型有三套完全相同的接口)
2. 路由冗余Handler 逻辑完全一样,却有三套路由)
3. 维护成本高(新增功能需要改三处)
4. 命名混乱(`customer-accounts` 实际管理企业账号)
5. **安全漏洞**(缺少越权检查,代理可以为其他店铺创建账号)
### Q2是否支持向后兼容
**A****不支持**。这是 Breaking Change旧接口已完全删除前端必须同步更新。
### Q3迁移需要多长时间
**A**
- 简单项目2-4 小时(主要是查找替换 + 测试)
- 复杂项目1-2 天(需要重构业务逻辑 + 测试回归)
### Q4后台和 H5 登录接口合并后如何区分?
**A**:不需要区分。后端通过用户类型自动判断:
- 超级管理员、平台用户:只能后台登录
- 代理用户:可以后台和 H5 登录
- 企业用户:只能 H5 登录
### Q5企业账号有什么特殊限制
**A**:企业账号**禁止访问账号管理接口**(路由层直接拦截),尝试访问会返回 403 错误。
### Q6新增了哪些安全功能
**A**
1. **三层越权防护**:路由层拦截 + Service 层权限检查 + GORM 自动过滤
2. **操作审计日志**:所有账号操作(创建、更新、删除、角色分配)都被记录
3. **统一错误返回**:越权访问返回"无权限操作该资源或资源不存在",防止信息泄露
### Q7如何区分不同账号类型
**A**:通过 `user_type` 字段区分:
- `user_type: 2` - 平台用户
- `user_type: 3` - 代理账号(需提供 `shop_id`
- `user_type: 4` - 企业账号(需提供 `enterprise_id`
## 新增功能
### 1. 企业账号完整功能
企业账号现在支持所有操作(之前只有部分功能):
- ✅ CRUD 操作
- ✅ 角色管理
- ✅ 密码管理
- ✅ 状态管理
### 2. 代理账号完整功能
代理账号现在支持所有操作(之前缺少角色管理):
- ✅ CRUD 操作
-**角色管理**(新增)
- ✅ 密码管理
- ✅ 状态管理
### 3. 统一路由结构
所有账号类型共享同一套接口,简化了前端开发:
- ✅ 减少重复代码
- ✅ 统一接口调用方式
- ✅ 更容易扩展新功能
## 支持
如有问题请联系后端团队或查看以下文档:
- [功能总结](./功能总结.md)
- [API 文档](./API文档.md)
- [OpenAPI 规范](../../docs/admin-openapi.yaml)