feat(iot-card-import): 为导入任务接口添加平台用户权限控制
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 6m10s
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 6m10s
- 在 Import/List/GetByID 接口添加用户类型校验 - 仅超级管理员和平台用户可访问 - 同步更新 OpenAPI 路由描述 - 补充集成测试覆盖权限拒绝场景
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
schema: spec-driven
|
||||
created: 2026-02-02
|
||||
@@ -0,0 +1,54 @@
|
||||
## Context
|
||||
|
||||
当前后台接口中,设备导入任务相关接口在 Handler 层做了“仅平台用户/超级管理员可访问”的用户类型校验(基于 `middleware.GetUserTypeFromContext` + `constants.UserTypeSuperAdmin/UserTypePlatform`)。
|
||||
|
||||
IoT 卡导入任务相关接口(提交导入、任务列表、任务详情)未做同等校验,导致权限边界与设备导入不一致。
|
||||
|
||||
本变更目标是将 IoT 卡导入任务相关接口的访问权限收敛为与设备导入一致:仅超级管理员与平台用户可访问。
|
||||
|
||||
## Goals / Non-Goals
|
||||
|
||||
**Goals:**
|
||||
- 对以下 3 个接口增加用户类型校验:仅允许超级管理员与平台用户访问。
|
||||
- 返回行为与现有模式一致:非允许用户类型直接返回 403(`errors.CodeForbidden`),错误消息使用中文。
|
||||
- OpenAPI 路由描述与实际权限一致。
|
||||
- 补齐/新增集成测试,覆盖非平台用户访问应被拒绝。
|
||||
|
||||
**Non-Goals:**
|
||||
- 不调整导入任务的数据模型与存储逻辑。
|
||||
- 不引入新的 RBAC 权限点或权限表配置(保持“用户类型硬校验”的现有风格)。
|
||||
- 不改动其他 IoT 卡管理接口的权限策略。
|
||||
|
||||
## Decisions
|
||||
|
||||
1) **在 Handler 层做用户类型校验(与设备导入对齐)**
|
||||
- 方案:在 `internal/handler/admin/iot_card_import.go` 的 `Import` / `List` / `GetByID` 入口处增加与 `internal/handler/admin/device_import.go` 同风格的校验。
|
||||
- 理由:
|
||||
- 与现有“设备导入”实现一致,减少认知负担。
|
||||
- 校验发生在参数解析与业务调用前,能最早拒绝无权限请求。
|
||||
- 备选方案:
|
||||
- 路由层中间件:更集中,但需要在路由注册处引入新中间件组合,且当前设备导入并未采用该方式。
|
||||
- Service 层校验:更“业务化”,但会改变当前导入模块的职责边界(设备导入限制目前在 Handler 层)。
|
||||
|
||||
2) **错误码与错误消息遵循现有约定**
|
||||
- 方案:使用 `errors.New(errors.CodeForbidden, "仅平台用户可...")` 风格,保持与设备导入一致。
|
||||
- 理由:该模块已有同类错误消息,避免引入新的错误码或文案风格。
|
||||
|
||||
3) **同步更新路由描述(OpenAPI)**
|
||||
- 方案:在 `internal/routes/iot_card.go` 对相关接口补充 `Description: "仅平台用户可操作。"`(与设备导入相同语义)。
|
||||
- 理由:避免文档与实际行为不一致,减少前后端联调成本。
|
||||
|
||||
## Risks / Trade-offs
|
||||
|
||||
- **[风险] 规格与实现不一致** → **缓解**:在本变更的 specs(delta spec)中明确将权限收敛为平台用户/超管,并在实现阶段对齐。
|
||||
- **[风险] 测试缺口导致回归** → **缓解**:新增集成测试覆盖非平台用户访问 403,并尽量复用现有测试基建(集成测试 env)。
|
||||
|
||||
## Migration Plan
|
||||
|
||||
- 该变更为权限收敛,无数据迁移。
|
||||
- 发布后影响:非平台用户/超管将无法调用 IoT 卡导入与导入任务查询接口。
|
||||
- 回滚策略:如业务需要恢复原可见性,可回滚本变更提交(或通过后续变更重新放开)。
|
||||
|
||||
## Open Questions
|
||||
|
||||
- 是否需要将错误消息文案统一为同一句(如“仅平台用户可操作”),还是分别保留更具体的文案(导入/列表/详情)?(实现阶段可按现有 device_import 文案对齐)
|
||||
@@ -0,0 +1,37 @@
|
||||
# 限制 IoT 卡导入任务接口仅平台用户可访问
|
||||
|
||||
Feature ID: feature-iot-card-import-task-platform-only
|
||||
|
||||
## Why
|
||||
|
||||
目前设备导入任务列表/详情已限制为仅平台用户/超级管理员可访问,但 IoT 卡导入任务列表/详情/提交导入未做同等限制,存在权限边界不一致与潜在越权风险。
|
||||
|
||||
需要将 IoT 卡导入任务相关接口的访问权限收敛为与设备导入一致,避免非平台账号通过后台接口获取或操作导入任务。
|
||||
|
||||
## What Changes
|
||||
|
||||
- **权限收敛**:IoT 卡导入相关接口仅允许超级管理员与平台用户访问;其他用户类型访问返回 403。
|
||||
- **接口范围**:
|
||||
- `POST /api/admin/iot-cards/import`
|
||||
- `GET /api/admin/iot-cards/import-tasks`
|
||||
- `GET /api/admin/iot-cards/import-tasks/:id`
|
||||
- **文档一致性**:补充路由描述,确保 OpenAPI 文档与实际权限一致。
|
||||
- **测试补齐**:新增/补充集成测试覆盖非平台用户访问上述接口应被拒绝。
|
||||
|
||||
## Capabilities
|
||||
|
||||
### New Capabilities
|
||||
|
||||
<!-- 无新增能力,本次为权限规则收敛 -->
|
||||
|
||||
### Modified Capabilities
|
||||
|
||||
- `iot-card-import-task`: 将“导入任务列表/详情/提交导入”的访问权限从“按 shop_id 数据权限过滤”调整为“仅平台用户/超级管理员可访问”。
|
||||
|
||||
## Impact
|
||||
|
||||
- 影响 API:`/api/admin/iot-cards/import`、`/api/admin/iot-cards/import-tasks`、`/api/admin/iot-cards/import-tasks/:id`
|
||||
- 预期涉及代码:
|
||||
- Handler:`internal/handler/admin/iot_card_import.go`
|
||||
- Routes/OpenAPI:`internal/routes/iot_card.go`
|
||||
- 集成测试:`tests/integration/iot_card_test.go`(或新增对应测试文件)
|
||||
@@ -0,0 +1,76 @@
|
||||
# iot-card-import-task Specification (Delta)
|
||||
|
||||
本变更用于收敛 IoT 卡导入任务相关接口的访问权限:仅超级管理员/平台用户可访问。
|
||||
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: 导入任务创建权限控制
|
||||
|
||||
系统 SHALL 仅允许超级管理员与平台用户创建 IoT 卡导入任务。
|
||||
|
||||
#### Scenario: 平台用户创建导入任务
|
||||
- **WHEN** 平台用户请求创建导入任务
|
||||
- **THEN** 系统创建导入任务并返回任务信息
|
||||
|
||||
#### Scenario: 非平台用户创建导入任务被拒绝
|
||||
- **WHEN** 非平台用户(代理账号/企业账号等)请求创建导入任务
|
||||
- **THEN** 系统返回 403(Forbidden),并返回统一错误码 `CodeForbidden`
|
||||
|
||||
## MODIFIED Requirements
|
||||
|
||||
### Requirement: 导入任务列表查询
|
||||
|
||||
系统 SHALL 支持查询导入任务列表,用于管理和监控导入任务。
|
||||
|
||||
**查询条件**:
|
||||
- 任务状态(status): 可选,1-待处理 2-处理中 3-已完成 4-失败
|
||||
- 运营商 ID(carrier_id): 可选
|
||||
- 批次号(batch_no): 可选,模糊匹配
|
||||
- 创建时间范围: 可选
|
||||
|
||||
**分页**:
|
||||
- 默认每页 20 条,最大每页 100 条
|
||||
- 默认按创建时间倒序排列
|
||||
|
||||
**权限**:
|
||||
- 仅超级管理员/平台用户可查询导入任务列表
|
||||
|
||||
#### Scenario: 查询所有导入任务
|
||||
|
||||
- **WHEN** 平台管理员查询导入任务列表
|
||||
- **THEN** 系统返回导入任务列表,包含任务编号、状态、运营商、总数、成功数、跳过数、失败数、创建时间
|
||||
|
||||
#### Scenario: 按状态筛选导入任务
|
||||
|
||||
- **WHEN** 平台管理员查询状态为 2(处理中) 的导入任务
|
||||
- **THEN** 系统返回所有正在处理的导入任务列表
|
||||
|
||||
#### Scenario: 非平台用户查询导入任务列表被拒绝
|
||||
|
||||
- **WHEN** 非平台用户(代理账号/企业账号等)查询导入任务列表
|
||||
- **THEN** 系统返回 403(Forbidden),并返回统一错误码 `CodeForbidden`
|
||||
|
||||
### Requirement: 导入任务详情查询
|
||||
|
||||
系统 SHALL 支持查询单个导入任务的详细信息,包括跳过/失败记录详情。
|
||||
|
||||
**详情信息**:
|
||||
- 任务基本信息: 任务编号、状态、运营商、批次号、文件名
|
||||
- 进度统计: 总数、成功数、跳过数、失败数
|
||||
- 时间信息: 创建时间、开始时间、完成时间
|
||||
- 跳过记录详情: 行号、ICCID、原因
|
||||
- 失败记录详情: 行号、ICCID、原因
|
||||
- 错误信息: 任务级错误(如有)
|
||||
|
||||
**权限**:
|
||||
- 仅超级管理员/平台用户可查询导入任务详情
|
||||
|
||||
#### Scenario: 查询导入任务详情
|
||||
|
||||
- **WHEN** 平台管理员查询导入任务(ID 为 1)的详情
|
||||
- **THEN** 系统返回任务完整信息,包括跳过和失败记录的详细列表
|
||||
|
||||
#### Scenario: 非平台用户查询导入任务详情被拒绝
|
||||
|
||||
- **WHEN** 非平台用户(代理账号/企业账号等)查询导入任务详情
|
||||
- **THEN** 系统返回 403(Forbidden),并返回统一错误码 `CodeForbidden`
|
||||
@@ -0,0 +1,18 @@
|
||||
## 1. 权限校验收敛(IoT 卡导入任务)
|
||||
|
||||
- [x] 1.1 在 `internal/handler/admin/iot_card_import.go` 的 `Import`/`List`/`GetByID` 增加用户类型校验:仅 `UserTypeSuperAdmin`/`UserTypePlatform` 允许访问,其余返回 `CodeForbidden`
|
||||
- [x] 1.2 校验错误消息文案与设备导入保持同风格(中文、明确动作),并确认不会泄露底层错误细节
|
||||
|
||||
## 2. 路由描述与文档一致性
|
||||
|
||||
- [x] 2.1 在 `internal/routes/iot_card.go` 为 `POST /iot-cards/import`、`GET /iot-cards/import-tasks`、`GET /iot-cards/import-tasks/:id` 补充 `Description: "仅平台用户可操作。"`
|
||||
|
||||
## 3. 测试补齐
|
||||
|
||||
- [x] 3.1 在集成测试中新增用例:非平台用户(至少覆盖代理账号)访问上述 3 个接口应返回 403(Forbidden)
|
||||
- [x] 3.2 运行并通过相关测试:`go test -v ./tests/integration/...`(如存在既有失败,需明确区分是否由本变更引入)
|
||||
|
||||
## 4. 本地验证
|
||||
|
||||
- [x] 4.1 对修改过的 Go 文件执行 `lsp_diagnostics` 确保无新增错误/告警
|
||||
- [x] 4.2 运行 `go test ./...` 做一次全量回归验证(如耗时可接受)
|
||||
@@ -81,6 +81,20 @@ TBD - created by archiving change iot-card-standalone-management. Update Purpose
|
||||
|
||||
---
|
||||
|
||||
### Requirement: 导入任务创建权限控制
|
||||
|
||||
系统 SHALL 仅允许超级管理员与平台用户创建 IoT 卡导入任务。
|
||||
|
||||
#### Scenario: 平台用户创建导入任务
|
||||
- **WHEN** 平台用户请求创建导入任务
|
||||
- **THEN** 系统创建导入任务并返回任务信息
|
||||
|
||||
#### Scenario: 非平台用户创建导入任务被拒绝
|
||||
- **WHEN** 非平台用户(代理账号/企业账号等)请求创建导入任务
|
||||
- **THEN** 系统返回 403(Forbidden),并返回统一错误码 `CodeForbidden`
|
||||
|
||||
---
|
||||
|
||||
### Requirement: 导入任务列表查询
|
||||
|
||||
系统 SHALL 支持查询导入任务列表,用于管理和监控导入任务。
|
||||
@@ -95,20 +109,24 @@ TBD - created by archiving change iot-card-standalone-management. Update Purpose
|
||||
- 默认每页 20 条,最大每页 100 条
|
||||
- 默认按创建时间倒序排列
|
||||
|
||||
**数据权限**:
|
||||
- 基于 shop_id 自动应用数据权限过滤
|
||||
- 代理只能看到自己店铺及下级店铺发起的导入任务
|
||||
**权限**:
|
||||
- 仅超级管理员/平台用户可查询导入任务列表
|
||||
|
||||
#### Scenario: 查询所有导入任务
|
||||
|
||||
- **WHEN** 管理员查询导入任务列表
|
||||
- **WHEN** 平台管理员查询导入任务列表
|
||||
- **THEN** 系统返回导入任务列表,包含任务编号、状态、运营商、总数、成功数、跳过数、失败数、创建时间
|
||||
|
||||
#### Scenario: 按状态筛选导入任务
|
||||
|
||||
- **WHEN** 管理员查询状态为 2(处理中) 的导入任务
|
||||
- **WHEN** 平台管理员查询状态为 2(处理中) 的导入任务
|
||||
- **THEN** 系统返回所有正在处理的导入任务列表
|
||||
|
||||
#### Scenario: 非平台用户查询导入任务列表被拒绝
|
||||
|
||||
- **WHEN** 非平台用户(代理账号/企业账号等)查询导入任务列表
|
||||
- **THEN** 系统返回 403(Forbidden),并返回统一错误码 `CodeForbidden`
|
||||
|
||||
---
|
||||
|
||||
### Requirement: 导入任务详情查询
|
||||
@@ -123,11 +141,19 @@ TBD - created by archiving change iot-card-standalone-management. Update Purpose
|
||||
- 失败记录详情: 行号、ICCID、原因
|
||||
- 错误信息: 任务级错误(如有)
|
||||
|
||||
**权限**:
|
||||
- 仅超级管理员/平台用户可查询导入任务详情
|
||||
|
||||
#### Scenario: 查询导入任务详情
|
||||
|
||||
- **WHEN** 管理员查询导入任务(ID 为 1)的详情
|
||||
- **WHEN** 平台管理员查询导入任务(ID 为 1)的详情
|
||||
- **THEN** 系统返回任务完整信息,包括跳过和失败记录的详细列表
|
||||
|
||||
#### Scenario: 非平台用户查询导入任务详情被拒绝
|
||||
|
||||
- **WHEN** 非平台用户(代理账号/企业账号等)查询导入任务详情
|
||||
- **THEN** 系统返回 403(Forbidden),并返回统一错误码 `CodeForbidden`
|
||||
|
||||
#### Scenario: 查询导入任务的跳过记录
|
||||
|
||||
- **WHEN** 管理员查询导入任务(ID 为 1)的跳过记录
|
||||
|
||||
Reference in New Issue
Block a user