Files
iotlcm/docs/openapi-permission-rollout.md
T
2026-10-29 14:49:18 +08:00

59 lines
5.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# v1.0.4 权限修复上线说明
受保护的 V3 接口仅在资源已启用、API 账号已启用、账号已分配权限组且权限组绑定该资源时放行。未登记资源、资源停用、账号不可用、未绑定权限组一律拒绝,不降级放行。
## 错误码
| 码 | 含义 | 触发条件 | 排查方向 |
|---|---|---|---|
| `10014` | 没有权限 | 资源未登记、资源停用、账号停用/不存在、账号无权限组、权限组未绑定该资源 | 业务与授权配置问题:查 `t_api_resource`、`t_api`、`t_api_group_resource` |
| `10016` | 权限校验失败 | 权限数据查询本身出错(如 `t_api_resource` 查询失败) | **系统侧故障**:查数据库连通性与表结构,不要按授权问题处理 |
两个码必须区分:数据库抖动时若复用 `10014`,运维会把系统故障误判成客户未授权。
## 上线前
1. 执行资源登记脚本 `iotlcm-database/SQL/20261016_openapi_resource_register.sql`。共 24 条 V3 路由,扣除 2 条取 token 入口后为 22 条受保护路由:**登记 15 条**,另 7 条已决定下线(`/common/*` 6 条 + `/change/traffic-cutoff-config` 1 条)。脚本幂等可重复执行,且不改动既有 `status`、`api_code`、`method`、`path`。
执行顺序:只读核对 → 登记(第 1 段)→ 计数校验应为 15 → 按实际授权范围绑定(第 3 段)。
2. 检查正在使用接口的账号对应 `t_api.group_id`,以及 `t_api_group_resource` 绑定。按已确认的授权范围补齐,**不能将所有资源自动赋给所有权限组**——那是扩大授权,属于安全倒退。
3. 资源登记使用完整请求路径与正确方法(`method=1` 即 POST)。查询与变更的 `traffic-cutoff-config` 路径前缀不同,分别登记。
4. 在验证环境检查:已授权接口正常;未登记/未授权/停用资源拒绝返回 `10014`;账号停用或无权限组拒绝;权限数据查询失败返回 `10016`。确认全部在用账号与接口后再部署生产。
## 免登录路径
`/openapi/v3/query/token` 与 `/openapi/v3/query/operator-token` 由配置 `router.exceptLogin` 控制,中间件内已无硬编码白名单。部署配置必须保留这两条,否则取 token 接口自身会被鉴权拦截而无法调用。
已确认 dev / preview / preview2 / prod 四套配置均含这两条。
## 重复路由的处置决定
代码中存在 12 条功能重叠的路由(`/common` 与 `/change` 各 6 条为同义路径)。判定分两层:先看**对外文档是否发布过**(发布过的必须保住),再看**业务是否确认在用**(业务确认不用的才硬删除)。
| 路径 | 决定 | 依据 |
|---|---|---|
| `/change/traffic-cutoff-config` | **下线**(不登记) | 从未写入对外文档(原始 common.md 只发布 4 个接口);与 `/change/batch-sim-traffic-cutoff` 参数类型、实现完全相同,控制器代码逐行重复,客户迁移无需改报文体;尾路径与只读的 `/query/traffic-cutoff-config` 同名,最易误调 |
| `/common/*`(6 条) | **已删除**(代码级,返回 404) | 业务确认真实客户只走 `/change/`,从不使用 `/common/`;该前缀是新增 `/change` 分组时未删旧分组的遗留,从未作为对外接口发布(原始 `common.md` 只发布 4 个 `/change` 接口) |
| `/change/renew` | **保留,登记授权,待观察** | 08-21 建立、09-10 才新增标准入口,存在早期接入客户;且入参只收 `cards[]`,与 `batch-sim-subscribe`(兼容平铺 `iccid[]`)不等价,不能直接判定为重复 |
| `/change/sim-subscribe`、`/change/sim-traffic-cutoff`(单卡)与对应批量接口 | **保留** | 已对外文档化,且同步单卡与异步批次是两套实现,粒度不同,非重复 |
两种下线方式的差别:
| | `/common/*` | `/change/traffic-cutoff-config` |
|---|---|---|
| 手段 | 删除 `internal/router/common.go`,`router.go` 不再调用 `Common()` | 不登记资源、不授权 |
| 客户端表现 | `404`(路由不存在) | `10014`(没有权限) |
| 恢复成本 | 需重新发版恢复路由,并补登记 6 条资源与授权 | 执行 SQL 文末的恢复语句即可,无需发版 |
| 选择理由 | 业务已确认无客户,该前缀无文档包袱,继续保留只会放大接口表面积与登记/授权工作量 | 参数与标准入口完全一致,但缺少「无人在用」的确认,需保住可逆性 |
`/change/renew` 上线后查调用日志,确认无调用再走「不登记」方式下线。
注意:`g.Meta` 的 `deprecated` 标签在 GoFrame v2.9.6 中不被解析,**没有运行时或文档生成效果**,不能作为废弃告知手段。对外废弃说明由 `openapi-docs` 承担。
## 回归验证
```
go test ./internal/logic/middleware -count=1
```
测试使用内存 SQLite,覆盖:数字/文本方法登记、路径规范化与末尾斜杠、未登记资源、方法不匹配、资源停用、缺失权限绑定、兼容入口独立授权(登记但未授权仍拒绝)、账号停用/无权限组/不存在、token 路径不在中间件白名单内,以及权限数据查询失败必须返回错误而非静默放行。