All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 5m9s
主要功能: - 添加企业卡授权/回收接口 (POST /enterprises/:id/allocate-cards, recall-cards) - 添加授权记录管理接口 (GET/PUT /authorizations) - 实现代理用户数据权限过滤(只能查看自己店铺下企业的授权记录) - 添加 GORM callback 支持授权记录表的数据权限过滤 技术改进: - 原生 SQL 查询手动添加数据权限过滤(ListWithJoin, GetByIDWithJoin) - 移除卡授权预检接口(allocate-cards/preview),保留内部方法 - 完善单元测试和集成测试覆盖
166 lines
5.5 KiB
Markdown
166 lines
5.5 KiB
Markdown
## Context
|
||
|
||
当前系统的企业卡授权功能存在权限控制不当的问题。现有实现使用 `asset_allocation_record` 表记录授权关系,但该表设计用于资产分配而非授权管理。此外,授权逻辑未正确实现单卡授权限制,权限控制不够精细。
|
||
|
||
**现状问题**:
|
||
- 授权记录存储位置不当(使用了资产分配表)
|
||
- 缺少对已绑定设备的卡的授权限制
|
||
- 企业可以看到不应该看到的商业敏感信息
|
||
- 权限控制逻辑分散,没有统一的授权管理
|
||
|
||
**技术约束**:
|
||
- 必须保持向后兼容,不能影响现有的卡分配功能
|
||
- 需要遵循项目的 GORM 数据权限自动过滤机制
|
||
- 不使用外键约束,关联通过代码层维护
|
||
|
||
## Goals / Non-Goals
|
||
|
||
**Goals:**
|
||
- 实现真正的单卡授权,授权不转移所有权
|
||
- 建立专用的授权记录表 `enterprise_card_authorization`
|
||
- 实现细粒度的权限控制,保护商业敏感数据
|
||
- 支持授权的创建、查询、回收全生命周期管理
|
||
- 与现有的 GORM 数据权限过滤机制无缝集成
|
||
|
||
**Non-Goals:**
|
||
- 不改变现有的卡分配(allocation)功能
|
||
- 不支持设备级授权(已绑定设备的卡不能单独授权)
|
||
- 不支持授权转移(必须先回收再重新授权)
|
||
- 不实现授权审批流程(直接授权生效)
|
||
|
||
## Decisions
|
||
|
||
### 1. 新建专用授权表
|
||
|
||
**决策**:创建 `enterprise_card_authorization` 表专门管理授权关系
|
||
|
||
**理由**:
|
||
- 授权和分配是两个不同的业务概念,应该分离存储
|
||
- 专用表可以更好地记录授权历史(包括回收记录)
|
||
- 避免污染现有的 `asset_allocation_record` 表结构
|
||
|
||
**备选方案**:
|
||
- 复用 `asset_allocation_record` 表:会混淆授权和分配的概念,且表结构不完全匹配
|
||
- 在 `iot_cards` 表添加授权字段:无法记录授权历史,且一张卡可能被多次授权/回收
|
||
|
||
### 2. 数据权限过滤集成
|
||
|
||
**决策**:通过修改现有的 IoT 卡查询逻辑,在 Store 层集成授权检查
|
||
|
||
**实现方式**:
|
||
```go
|
||
// 企业用户查询时的过滤逻辑
|
||
if userType == UserTypeEnterprise {
|
||
db = db.Where("owner_type = ? AND owner_id = ?", "enterprise", enterpriseID).
|
||
Or(db.Where("id IN (?)",
|
||
db.Table("enterprise_card_authorization").
|
||
Select("card_id").
|
||
Where("enterprise_id = ? AND revoked_at IS NULL", enterpriseID)))
|
||
}
|
||
```
|
||
|
||
**理由**:
|
||
- 利用现有的 GORM Callback 机制,自动应用权限过滤
|
||
- 保持查询接口不变,上层代码无需修改
|
||
- 统一的权限控制点,易于维护
|
||
|
||
### 3. 敏感信息过滤
|
||
|
||
**决策**:在 Handler 层对响应数据进行后处理,移除敏感字段
|
||
|
||
**实现方式**:
|
||
- Service 层返回完整数据
|
||
- Handler 层检查用户类型,如果是企业用户则清空敏感字段
|
||
- 敏感字段:`cost_price`、`distribute_price`、`supplier`
|
||
|
||
**理由**:
|
||
- 保持 Service 层的通用性,不同场景可能需要不同的字段过滤
|
||
- Handler 层更接近展示层,适合做展示相关的数据处理
|
||
- 便于未来扩展不同用户类型的字段过滤规则
|
||
|
||
### 4. 批量授权接口设计
|
||
|
||
**决策**:提供单一的批量授权接口,不单独提供预检接口
|
||
|
||
**接口结构**:
|
||
```go
|
||
// 请求
|
||
POST /api/admin/enterprises/{enterpriseId}/authorize-cards
|
||
{
|
||
"card_ids": [1, 2, 3]
|
||
}
|
||
|
||
// 响应
|
||
{
|
||
"success": [
|
||
{"card_id": 1, "iccid": "8986..."}
|
||
],
|
||
"failed": [
|
||
{"card_id": 2, "iccid": "8986...", "reason": "卡已绑定设备"},
|
||
{"card_id": 3, "iccid": "8986...", "reason": "卡状态不是已分销"}
|
||
]
|
||
}
|
||
```
|
||
|
||
**理由**:
|
||
- 减少网络往返,提高性能
|
||
- 简化前端实现,一次调用获得所有结果
|
||
- 支持部分成功的场景,提高容错性
|
||
|
||
## Risks / Trade-offs
|
||
|
||
### 性能风险
|
||
|
||
**风险**:企业用户查询卡列表时需要 JOIN 授权表,可能影响查询性能
|
||
|
||
**缓解措施**:
|
||
- 在 `enterprise_card_authorization` 表的 `enterprise_id` 和 `revoked_at` 字段建立联合索引
|
||
- 在 `card_id` 字段建立索引支持反向查询
|
||
- 考虑未来使用 Redis 缓存授权关系
|
||
|
||
### 数据一致性
|
||
|
||
**风险**:授权记录和卡状态可能不一致(如卡被删除但授权记录还在)
|
||
|
||
**缓解措施**:
|
||
- 使用软删除,保留历史数据
|
||
- 定期运行数据一致性检查任务
|
||
- 在查询时过滤已删除的卡
|
||
|
||
### 权限泄露风险
|
||
|
||
**风险**:敏感信息过滤不完整可能导致商业数据泄露
|
||
|
||
**缓解措施**:
|
||
- 在 Handler 层统一处理,确保所有接口都经过过滤
|
||
- 添加单元测试验证敏感字段确实被过滤
|
||
- 考虑使用 DTO 模式,为不同用户类型定义不同的响应结构
|
||
|
||
## Migration Plan
|
||
|
||
### 部署步骤
|
||
|
||
1. **数据库迁移**
|
||
- 创建 `enterprise_card_authorization` 表
|
||
- 添加必要的索引
|
||
|
||
2. **代码部署**
|
||
- 部署新的授权管理代码
|
||
- 保持旧的分配接口正常工作
|
||
|
||
3. **数据迁移**(如需要)
|
||
- 如果有历史授权数据在 `asset_allocation_record` 表,编写迁移脚本
|
||
- 迁移完成后可以清理旧数据
|
||
|
||
### 回滚策略
|
||
|
||
- 代码支持功能开关,可通过配置禁用新的授权功能
|
||
- 数据库表独立,不影响现有功能,可保留表结构
|
||
- 如需完全回滚,删除新表并恢复旧代码
|
||
|
||
## Open Questions
|
||
|
||
1. **授权有效期**:是否需要支持授权有效期?目前设计是永久授权直到主动回收
|
||
2. **授权数量限制**:是否需要限制一个企业可以被授权的卡数量?
|
||
3. **通知机制**:授权/回收时是否需要通知企业?
|
||
4. **审计日志**:是否需要更详细的授权操作日志? |