供应商接口接入网关与权限矩阵(#6191)
changelog-filename-gate / validate (push) Successful in 2s

这个提交包含在:
lc
2026-08-23 10:27:35 +08:00
父节点 da7f0d888a
当前提交 cda1516aee
@@ -0,0 +1,169 @@
---
schema: "hl-changelog/v2"
ticket: "6191"
title: "供应商管理接口接入 Gateway 强制认证并启用最小角色权限矩阵"
consumer: "admin"
author: "lc(GIT)"
change_type: "修改接口"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "not_required"
frontend_owner: ""
frontend_ref: ""
target_release: ""
verified_at: ""
status_note: "PR #6192 与补充 PR #6194 已合并 dev-v3,最终提交 5d144c962 已部署 TEST。真实账号登录及角色切换实测:匿名和伪造身份返回业务码 401;ADMIN、FINANCE、SUPER_ADMIN、CUSTOMIZER 的十项供应商权限分别为 3、9、10、0;越权写入返回 395002/395004;临时身份、日志和精确缓存已清理。无前端、菜单或按钮改动。"
updated_at: "2026-08-23"
base: "dev-v3"
---
# 供应商管理:Gateway 强制认证与最小角色权限矩阵
本次只改变现有供应商管理接口的入口和服务端授权行为,不新增接口,也不改变请求字段、响应字段或业务错误码。所有 `/admin/supplier/**` 请求现在统一经 Gateway 路由到资源服务,并要求真实管理员登录态;菜单是否可见不再等同于服务端授权。
## 关键变化
| 场景 | 修改前 | 修改后 |
|------|--------|--------|
| Gateway 路由 | `/admin/supplier/**` 未纳入资源服务路由 | 路由到资源服务并执行强制认证 |
| 未登录或伪造身份头 | 无稳定的供应商入口保护契约 | 统一响应业务码 `401`,请求不会进入供应商业务 |
| 角色授权 | 供应商权限定义与角色绑定不完整 | 按 ADMIN 3 项、FINANCE 9 项、SUPER_ADMIN 10 项、其他角色 0 项收紧 |
| 凭证地址 | 仅依赖业务接口自身行为 | 只有 `supplier:account:proof:read` 才会在账户详情中返回凭证 URL |
## 变更接口清单
以下现有接口均纳入同一 Gateway 路由与权限门禁;入参、出参保持不变。
| # | 方法 | 路径 | 权限 |
|---:|------|------|------|
| 1 | GET | `/admin/supplier/items/page` | `supplier:list` |
| 2 | GET | `/admin/supplier/items/list` | `supplier:list` |
| 3 | GET | `/admin/supplier/items/{supplierId}/basic-info/view` | `supplier:view` |
| 4 | POST | `/admin/supplier/items/add` | `supplier:create` |
| 5 | PUT | `/admin/supplier/items/{supplierId}/update` | `supplier:update` |
| 6 | POST | `/admin/supplier/items/{supplierId}/submit` | `supplier:update` + `supplier:approval:submit` |
| 7 | POST | `/admin/supplier/items/{supplierId}/archive` | `supplier:status:manage` |
| 8 | DELETE | `/admin/supplier/items/{supplierId}/del` | `supplier:delete` |
| 9 | GET | `/admin/supplier/items/{supplierId}/approval-records/page` | `supplier:approval:read` |
| 10 | GET | `/admin/supplier/items/{supplierId}/account-info/list` | `supplier:view` |
| 11 | POST | `/admin/supplier/items/{supplierId}/bank-accounts/add` | `supplier:account:manage` + `supplier:approval:submit` |
| 12 | GET | `/admin/supplier/bank-accounts/{accountId}/view` | `supplier:view`;凭证 URL 另需 `supplier:account:proof:read` |
| 13 | PUT | `/admin/supplier/bank-accounts/{accountId}/default/update` | `supplier:account:manage` |
## 权限矩阵
| 权限 | ADMIN | FINANCE | SUPER_ADMIN | CUSTOMIZER/其他 |
|------|:-----:|:-------:|:-----------:|:---------------:|
| `supplier:list` | ✓ | ✓ | ✓ | — |
| `supplier:view` | ✓ | ✓ | ✓ | — |
| `supplier:approval:read` | ✓ | ✓ | ✓ | — |
| `supplier:create` | — | ✓ | ✓ | — |
| `supplier:update` | — | ✓ | ✓ | — |
| `supplier:approval:submit` | — | ✓ | ✓ | — |
| `supplier:account:manage` | — | ✓ | ✓ | — |
| `supplier:account:proof:read` | — | ✓ | ✓ | — |
| `supplier:delete` | — | ✓ | ✓ | — |
| `supplier:status:manage` | — | — | ✓ | — |
权限同时检查 Gateway 下传的可信角色和 User 权限点。仅有菜单或按钮权限不能绕过服务端门禁,客户端传入的 `X-Admin-Id`、`X-Admin-Role` 也不能替代有效 Token。
## 代表性调用与响应
### 已登录角色查询供应商列表
```http
GET /admin/supplier/items/page?page=1&pageSize=10
Authorization: Bearer <管理员访问令牌>
```
请求无 Body。请求和成功响应结构未变,典型成功包络如下:
```json
{
"code": 200,
"message": "成功",
"data": {
"records": [],
"total": 0,
"page": 1,
"pageSize": 10
},
"success": true
}
```
### 未登录或仅伪造身份头
```json
{
"code": 401,
"message": "缺少有效的 Authorization 头",
"data": null,
"success": false
}
```
项目统一包络可能以 HTTP 200 承载业务失败,调用方必须检查 `code` 和 `success`。
### ADMIN 尝试创建供应商
```json
{
"code": 395002,
"message": "无权执行该供应商写操作",
"data": null,
"success": false
}
```
### FINANCE 尝试归档供应商
```json
{
"code": 395004,
"message": "无权执行该供应商状态操作",
"data": null,
"success": false
}
```
## 边界与兼容性
- 请求和响应字段、分页参数、供应商状态机、审批语义、错误码均未修改。
- 未新增 `sys_menu`,也未修改任何前端菜单、按钮或页面;前端无需同步发布。
- 账户详情中的凭证 URL 只按独立权限裁剪。本工单不新增文件 URL、文件状态或访问归属校验。
- 本工单只补供应商权限和路由,不扩大到公共 Feign、文件服务或其他业务模块。
- 无效 Token、伪造身份头和非目标角色均失败关闭,不产生供应商业务写入。
## 验证证据
- 最终部署提交:`5d144c962c3812d6adf23361e1d9d86ae01f3199`。
- Gateway 真实请求:匿名与伪造 `X-Admin-*` 身份均返回业务码 `401`;供应商路径命中 `hl-resource-service` 路由。
- 使用临时 TEST 管理员通过 `/admin/auth/login` 登录,并依次调用 `/admin/auth/switch-role`:
- SUPER_ADMIN:十项权限 `10/10`;
- ADMIN:仅三项读取权限 `3/10`,创建返回 `395002`;
- FINANCE:除生命周期管理外 `9/10`,凭证读取为 `true`,归档返回 `395004`;
- CUSTOMIZER:`0/10`,读取返回 `403`。
- 当前 TEST 的供应商类型字典基线未初始化,已授权的列表请求在通过 Gateway 与权限门禁后进入既有下游检查并返回 `395039`;该依赖数据不在本工单改动范围。权限链路、拒绝语义和零写入均已实测。
- 临时管理员、角色关系、登录日志、操作日志及对应 Redis Token/权限缓存均已精确删除;供应商业务表行数前后不变。
- 自动化回归:Gateway 定向 `8/8`、User 供应商迁移 `5/5`、Resource 供应商 `19/19`;User 全量 `3588`、Resource 全量 `1855`、Gateway 排除既有无关 Fleet 跨库审计后 `80` 项全部通过;24 模块构建通过。
## 影响评估
- **是否破坏向后兼容**:否。接口字段与业务动作不变,只补齐原本缺失的入口和授权边界。
- **前端是否必须同步上线**:否。
- **前端 workaround 清理点**:无;继续使用现有登录 Token,不要自行构造管理员身份头。
## 关联 / 联系人
### 链接
- **Issue**: [#6191](https://git.1814.love:8443/wx/HL/issues/6191)
- **主 PR**: [#6192](https://git.1814.love:8443/wx/HL/pulls/6192)
- **权限元数据补充 Issue**: [#6193](https://git.1814.love:8443/wx/HL/issues/6193)
- **权限元数据补充 PR**: [#6194](https://git.1814.love:8443/wx/HL/pulls/6194)
- **最终合并提交**: [5d144c962](https://git.1814.love:8443/wx/HL/commit/5d144c962c3812d6adf23361e1d9d86ae01f3199)
### 联系人
- **后端负责人**: @lc