Files
junhong_cmp_fiber/docs/前端建设/权限矩阵与接口联调契约.md
break 5ba227eff5
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 1m8s
111
2026-07-29 14:58:28 +08:00

12 KiB
Raw Blame History

权限矩阵与接口联调契约

一、管理端权限计算模型

管理页面和操作的最终可用性不是只看 user_type,而是四个条件的交集:

终端适用范围 web/h5/all
        ∩
账号所绑定角色的菜单和按钮权限
        ∩
账号身份的硬性业务限制
        ∩
当前组织的数据范围

1.1 终端

权限记录包含 platform

  • web:只在管理 Web 登录时返回。
  • h5:只在管理 H5 登录时返回。
  • all:两端都返回。

1.2 角色

  • 超级管理员不分配角色。
  • 平台账号使用平台角色,可绑定多个。
  • 代理和企业账号使用客户角色,最多绑定一个。
  • 登录返回 menusbuttons 和兼容字段 permissions

因此,“代理可用什么”应由给该代理账号绑定的客户角色决定,而不是维护一套固定代理菜单。

1.3 身份硬限制

角色权限不能突破组织身份的业务限制。例如:

  • 企业账号即使错误分配了店铺菜单,也不应管理店铺。
  • 企业账号不应访问代理资金、佣金、提现和代理充值。
  • 代理账号不能越过本店及下级店铺的数据范围。
  • 代理账号不能管理平台直属企业。
  • 只有超管或平台管理身份可以维护支付、企微和全局系统配置。

1.4 数据范围

用户身份 组织字段 正常数据范围
超级管理员 全平台
平台账号 全平台,但功能仍受角色权限控制
代理账号 shop_id 本店及全部下级店铺
企业账号 enterprise_id 本企业有效授权资产和本企业业务记录
个人客户 customer_id 本人绑定资产及本人订单、充值、通知

二、目标权限矩阵

下表是产品和安全目标,不代表当前每条后端接口都已完整实现。

图例:

  • 权限控制:角色有相应菜单/按钮且数据范围满足时可用。
  • 范围受限:可用,但只能处理当前组织范围。
  • 只读建议:首期只开放查询。
  • 禁止:角色配置也不得突破。
业务模块 超管 平台账号 代理账号 企业账号 个人客户
账号管理 全部 权限控制 范围受限 禁止 不适用
角色/权限配置 全部 权限控制 建议禁止 禁止 不适用
店铺管理 全部 权限控制 本店及下级、权限控制 禁止 不适用
企业管理 全部 权限控制 本店及下级企业、权限控制 只读本企业资料 不适用
企业资产授权 全部 权限控制 本店及下级企业、权限控制 只读本企业授权 不适用
卡/设备库存 全部 权限控制 本店及下级、权限控制 仅本企业授权资产 仅本人绑定资产
资产分配 全部 权限控制 通常仅直属下级、权限控制 禁止 禁止
资产状态与设备控制 全部 权限控制 范围受限、权限控制 本企业授权范围、权限控制 本人绑定范围
运营商配置 全部 权限控制 禁止 禁止 不适用
套餐系列/套餐设计 全部 权限控制 建议只读 禁止 只看可购投影
套餐授权/分配/定价 全部 权限控制 直属下级、权限控制 禁止 禁止
管理端订单 全部 权限控制 范围受限、权限控制 视业务角色决定 仅本人 C 端订单
退款/换货 全部 权限控制 范围受限、权限控制 只读建议 C 端只提交换货收货信息
代理主钱包/佣金/提现 全部 权限控制 本店及下级、权限控制 禁止 不适用
代理充值 全部 权限控制 本店在线充值、权限控制 禁止 不适用
资产钱包 全部 权限控制 范围受限、权限控制 授权资产只读建议 本人绑定资产
导入/批量处理 全部 权限控制 范围受限、权限控制 禁止 禁止
导出 全部 权限控制 按数据范围导出 只导本企业且需明确开放 禁止
微信/支付宝/企微配置 全部 权限控制 禁止 禁止 禁止
轮询、告警、清理 全部 权限控制 只读建议 禁止 禁止
通知 全部 当前账号 当前账号 当前账号 当前客户

三、统一认证契约

3.1 管理 Web/H5 登录

POST /api/auth/login
Content-Type: application/json
{
  "username": "账号或手机号",
  "password": "密码",
  "device": "web"
}

管理 H5 将 device 改为 h5

成功后保存:

{
  "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": []
}

所有受保护请求携带:

Authorization: Bearer <access_token>

3.2 Token 刷新

POST /api/auth/refresh-token
{
  "refresh_token": "..."
}

前端请求模块需要实现单次刷新队列:多个并发请求同时收到 401 时,只允许一个请求刷新 Token其余等待结果刷新失败统一清除会话并跳转登录。

3.3 C 端认证

C 端使用 /api/c/v1/auth/*,不使用管理端登录或刷新 Token

  1. verify-asset
  2. wechat-loginminiapp-login
  3. 必要时 bind-phone
  4. 后续请求携带 C 端 Bearer Token。
  5. 认证失效重新走资产验证和微信登录。

四、响应与错误契约

4.1 统一响应

{
  "code": 0,
  "msg": "success",
  "data": {},
  "timestamp": "2026-07-29T12:00:00+08:00"
}

前端成功判断必须同时尊重 HTTP 状态和业务 code,不能只判断 HTTP 200。

4.2 分页

常见请求参数为 pagepage_size,常见返回为:

{
  "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-cardsallocate-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_xxxh5_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. 路由和 DTOinternal/routesinternal/model/dto
  2. 机器可读契约:docs/admin-openapi.yaml
  3. 业务和页面组合:docs/前端建设
  4. 七月迭代新增字段:docs/7月迭代/七月迭代实现与接口对接说明.md

发现接口与 OpenAPI 不一致时,先修正文档生成器和 DTO不在前端编写长期兼容分支掩盖契约问题。