111
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 1m8s

This commit is contained in:
2026-07-29 14:58:28 +08:00
parent eea19f2a5b
commit 5ba227eff5
5 changed files with 1027 additions and 0 deletions

View File

@@ -0,0 +1,306 @@
# 权限矩阵与接口联调契约
## 一、管理端权限计算模型
管理页面和操作的最终可用性不是只看 `user_type`,而是四个条件的交集:
```text
终端适用范围 web/h5/all
账号所绑定角色的菜单和按钮权限
账号身份的硬性业务限制
当前组织的数据范围
```
### 1.1 终端
权限记录包含 `platform`
- `web`:只在管理 Web 登录时返回。
- `h5`:只在管理 H5 登录时返回。
- `all`:两端都返回。
### 1.2 角色
- 超级管理员不分配角色。
- 平台账号使用平台角色,可绑定多个。
- 代理和企业账号使用客户角色,最多绑定一个。
- 登录返回 `menus``buttons` 和兼容字段 `permissions`
因此,“代理可用什么”应由给该代理账号绑定的客户角色决定,而不是维护一套固定代理菜单。
### 1.3 身份硬限制
角色权限不能突破组织身份的业务限制。例如:
- 企业账号即使错误分配了店铺菜单,也不应管理店铺。
- 企业账号不应访问代理资金、佣金、提现和代理充值。
- 代理账号不能越过本店及下级店铺的数据范围。
- 代理账号不能管理平台直属企业。
- 只有超管或平台管理身份可以维护支付、企微和全局系统配置。
### 1.4 数据范围
| 用户身份 | 组织字段 | 正常数据范围 |
| --- | --- | --- |
| 超级管理员 | 无 | 全平台 |
| 平台账号 | 无 | 全平台,但功能仍受角色权限控制 |
| 代理账号 | `shop_id` | 本店及全部下级店铺 |
| 企业账号 | `enterprise_id` | 本企业有效授权资产和本企业业务记录 |
| 个人客户 | `customer_id` | 本人绑定资产及本人订单、充值、通知 |
## 二、目标权限矩阵
下表是产品和安全目标,不代表当前每条后端接口都已完整实现。
图例:
- `权限控制`:角色有相应菜单/按钮且数据范围满足时可用。
- `范围受限`:可用,但只能处理当前组织范围。
- `只读建议`:首期只开放查询。
- `禁止`:角色配置也不得突破。
| 业务模块 | 超管 | 平台账号 | 代理账号 | 企业账号 | 个人客户 |
| --- | --- | --- | --- | --- | --- |
| 账号管理 | 全部 | 权限控制 | 范围受限 | 禁止 | 不适用 |
| 角色/权限配置 | 全部 | 权限控制 | 建议禁止 | 禁止 | 不适用 |
| 店铺管理 | 全部 | 权限控制 | 本店及下级、权限控制 | 禁止 | 不适用 |
| 企业管理 | 全部 | 权限控制 | 本店及下级企业、权限控制 | 只读本企业资料 | 不适用 |
| 企业资产授权 | 全部 | 权限控制 | 本店及下级企业、权限控制 | 只读本企业授权 | 不适用 |
| 卡/设备库存 | 全部 | 权限控制 | 本店及下级、权限控制 | 仅本企业授权资产 | 仅本人绑定资产 |
| 资产分配 | 全部 | 权限控制 | 通常仅直属下级、权限控制 | 禁止 | 禁止 |
| 资产状态与设备控制 | 全部 | 权限控制 | 范围受限、权限控制 | 本企业授权范围、权限控制 | 本人绑定范围 |
| 运营商配置 | 全部 | 权限控制 | 禁止 | 禁止 | 不适用 |
| 套餐系列/套餐设计 | 全部 | 权限控制 | 建议只读 | 禁止 | 只看可购投影 |
| 套餐授权/分配/定价 | 全部 | 权限控制 | 直属下级、权限控制 | 禁止 | 禁止 |
| 管理端订单 | 全部 | 权限控制 | 范围受限、权限控制 | 视业务角色决定 | 仅本人 C 端订单 |
| 退款/换货 | 全部 | 权限控制 | 范围受限、权限控制 | 只读建议 | C 端只提交换货收货信息 |
| 代理主钱包/佣金/提现 | 全部 | 权限控制 | 本店及下级、权限控制 | 禁止 | 不适用 |
| 代理充值 | 全部 | 权限控制 | 本店在线充值、权限控制 | 禁止 | 不适用 |
| 资产钱包 | 全部 | 权限控制 | 范围受限、权限控制 | 授权资产只读建议 | 本人绑定资产 |
| 导入/批量处理 | 全部 | 权限控制 | 范围受限、权限控制 | 禁止 | 禁止 |
| 导出 | 全部 | 权限控制 | 按数据范围导出 | 只导本企业且需明确开放 | 禁止 |
| 微信/支付宝/企微配置 | 全部 | 权限控制 | 禁止 | 禁止 | 禁止 |
| 轮询、告警、清理 | 全部 | 权限控制 | 只读建议 | 禁止 | 禁止 |
| 通知 | 全部 | 当前账号 | 当前账号 | 当前账号 | 当前客户 |
## 三、统一认证契约
### 3.1 管理 Web/H5 登录
```http
POST /api/auth/login
Content-Type: application/json
```
```json
{
"username": "账号或手机号",
"password": "密码",
"device": "web"
}
```
管理 H5 将 `device` 改为 `h5`
成功后保存:
```json
{
"access_token": "...",
"refresh_token": "...",
"expires_in": 86400,
"user": {
"id": 1,
"username": "admin",
"user_type": 2,
"user_type_name": "平台用户",
"shop_id": 0,
"enterprise_id": 0
},
"menus": [],
"buttons": [],
"permissions": []
}
```
所有受保护请求携带:
```http
Authorization: Bearer <access_token>
```
### 3.2 Token 刷新
```http
POST /api/auth/refresh-token
```
```json
{
"refresh_token": "..."
}
```
前端请求模块需要实现单次刷新队列:多个并发请求同时收到 401 时,只允许一个请求刷新 Token其余等待结果刷新失败统一清除会话并跳转登录。
### 3.3 C 端认证
C 端使用 `/api/c/v1/auth/*`,不使用管理端登录或刷新 Token
1. `verify-asset`
2. `wechat-login``miniapp-login`
3. 必要时 `bind-phone`
4. 后续请求携带 C 端 Bearer Token。
5. 认证失效重新走资产验证和微信登录。
## 四、响应与错误契约
### 4.1 统一响应
```json
{
"code": 0,
"msg": "success",
"data": {},
"timestamp": "2026-07-29T12:00:00+08:00"
}
```
前端成功判断必须同时尊重 HTTP 状态和业务 `code`,不能只判断 HTTP 200。
### 4.2 分页
常见请求参数为 `page``page_size`,常见返回为:
```json
{
"items": [],
"total": 0,
"page": 1,
"size": 20
}
```
不同历史模块的列表 DTO 可能有差异,类型生成和页面开发必须以对应 OpenAPI Operation 为准,不能强制假设所有列表结构完全相同。
### 4.3 HTTP 错误处理
| HTTP 状态 | 前端行为 |
| --- | --- |
| 400 | 定位请求字段,展示后端安全中文提示 |
| 401 | 管理端尝试刷新C 端重新登录 |
| 403 | 显示无权限,不重试,不猜测资源是否存在 |
| 404 | 显示资源不存在或已失效 |
| 409 | 提示状态已变化,重新拉取详情 |
| 429 | 提示操作频繁,按 `Retry-After` 或短时退避 |
| 5xx | 展示通用错误和 Request ID允许用户手动重试 |
## 五、数据展示契约
- 金额:接口整数单位通常为分,展示时格式化为元,提交时转换回分;禁止浮点数直接参与计算。
- 状态:优先使用响应中的 `status_name``*_name`,不要在多个前端重复维护中文枚举。
- 时间:按 ISO 8601 解析,统一展示为当前业务时区;提交日期范围按接口约定处理起止边界。
- ID前端将 ID 当作不透明标识,不参与金额或业务计算。
- 空值:区分 `null`、空字符串、0 和空数组,不能用统一假值替换。
- 资产标识:按字符串保存和上传,避免 ICCID 被转为科学计数法或丢失前导零。
- 支付方式:使用 `allowed_payment_methods` 或支付方式查询接口,不写死微信/支付宝/钱包组合。
- 状态流转:按钮是否出现先看权限和当前状态;提交后仍以后端状态机结果为准。
## 六、关键接口调用顺序
### 6.1 管理端创建订单
1. 解析或选择资产。
2. 查询资产可用套餐。
3. `POST /api/admin/orders/purchase-check`
4. 展示后端计算的购买条件、金额和支付方式。
5. `POST /api/admin/orders`
6. 查询订单详情确认最终状态。
### 6.2 代理在线充值
1. `GET /api/admin/agent-recharges/payment-methods`
2. `POST /api/admin/agent-recharges`
3. 按响应拉起支付。
4. 轮询 `GET /api/admin/agent-recharges/:id/payment-status`
5. 查询详情和主钱包流水确认到账。
### 6.3 企业资产授权
1. 查询企业详情。
2. 查询候选卡或设备。
3. 提交 `allocate-cards``allocate-devices`
4. 重新查询企业卡/设备列表。
5. 查询授权记录确认结果。
设备授权由后端同步处理绑定卡,前端不得自行拆分请求。
### 6.4 文件上传和异步任务
1. `POST /api/admin/storage/upload-url`
2. 直接向响应的对象存储 URL 上传。
3.`file_key` 提交业务任务接口。
4. 轮询任务详情。
5. 完成后展示结果或下载文件。
### 6.5 第三方支付
1. 创建业务订单或充值单。
2. 使用后端返回的支付参数/链接拉起支付。
3. 支付平台回调只由服务端接收,前端不得调用 `/api/callback/*`
4. 用户返回页面后重新查询业务单状态。
5. 结果未知时保持“处理中”,不在前端直接改为成功。
## 七、管理 Web/H5 的路由和权限约定
1. 登录后以 `menus[].url` 建立可访问路由白名单。
2. 路由守卫同时检查登录状态和菜单权限。
3. 按钮组件检查 `buttons`,但按钮隐藏只负责体验,不是安全门禁。
4. Web/H5 使用同一权限码,不创建 `web_xxx``h5_xxx` 两套业务权限码;终端差异使用权限记录的 `platform` 字段。
5. 不给当前终端返回的菜单不得通过手输 URL 进入。
6. 页面加载收到 403 后应移除当前不可用操作并提示重新登录获取最新权限。
## 八、联调验收矩阵
每个管理接口至少使用以下账号验证:
| 用例 | 超管 | 有权限平台 | 无权限平台 | 有权限代理 | 越权代理 | 企业账号 |
| --- | --- | --- | --- | --- | --- | --- |
| 菜单是否返回 | 验证 | 验证 | 不返回 | 验证 | 验证 | 验证 |
| 页面能否进入 | 验证 | 验证 | 禁止 | 验证 | 视权限 | 视权限 |
| API 能否调用 | 验证 | 验证 | 403 | 验证 | 403/空范围 | 仅目标能力 |
| 列表数据范围 | 全部 | 全部 | 无调用 | 本店及下级 | 不含平级/上级 | 仅本企业 |
| 详情越权 | 可见 | 可见 | 403 | 非范围资源 403 | 403 | 非本企业 403 |
| 写操作越权 | 可操作 | 按权限 | 403 | 仅允许范围 | 403 | 仅明确开放能力 |
C 端接口至少覆盖本人绑定资产、本人未绑定资产、其他客户订单、Token 被新登录替换、资产解绑、店铺禁止新 C 端登录。
## 九、当前后端安全缺口
以下问题是上线门禁,不应交给前端规避:
1. `/api/admin` 当前统一挂载认证中间件,但没有发现逐路由普遍挂载 `RequirePermission`
2. 当前 `menus/buttons` 主要用于前端显示,不能证明每个接口已做相同权限校验。
3. 部分接口明确说明按钮权限不在后端校验。
4. 企业账号没有店铺下级范围,部分使用宽松店铺过滤的查询可能需要专项验证。
5. 企业、企业授权、卡和设备列表需要使用真实企业 Token 做越权测试。
前端可以按权限正确隐藏界面,但生产上线前必须由后端补齐或验证:
- 功能权限门禁。
- 资源级权限校验。
- 企业数据范围。
- 写操作状态机和幂等。
- 敏感配置和高风险动作的身份限制。
## 十、联调权威来源
1. 路由和 DTO`internal/routes``internal/model/dto`
2. 机器可读契约:`docs/admin-openapi.yaml`
3. 业务和页面组合:`docs/前端建设`
4. 七月迭代新增字段:`docs/7月迭代/七月迭代实现与接口对接说明.md`
发现接口与 OpenAPI 不一致时,先修正文档生成器和 DTO不在前端编写长期兼容分支掩盖契约问题。