Files
nexus/Project/fonrey/TECH_STACK/权限管理系统技术方案.md
2026-04-30 20:33:51 +08:00

270 lines
8.0 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.
> **For AI assistants**: Read this entire file before writing any code. All decisions here are final. Do not suggest alternatives unless asked.
# Fonrey 权限管理技术方案
**版本**: 2.1
**项目**: Fonrey 房产经纪管理系统
**技术栈**: Django 4.x + HTMX + Alpine.js + PostgreSQL 16 + Redis
**关联 PRD**: `PRD/权限管理/权限管理模块PRD.md`
**关联数据模型**: `DATA_MODEL/DATA_MODEL_PERMISSION.md`(本方案不重复 DDL
**关联契约规范**: `TECH_STACK/API_CONTRACT.md`(全局 API 契约权威)
**最后更新**: 2026-04-27
---
## 变更历史
| 日期 | 变更人 | 变更内容 |
|---|---|---|
| 2026-04-30 | Atlas | 补充“变更历史”章节(文档治理) |
## 一、文档定位与边界
本文件仅定义权限模块的:
1. RBAC + 个人覆盖架构边界
2. 权限解析/合并与门禁约束
3. API 端点设计(页面 / HTMX / JSON
4. 缓存一致性与审计策略
5. 错误码与测试映射
> 不在本文件展开权限相关表字段与索引。数据结构以 `DATA_MODEL_PERMISSION.md` 为唯一权威。
---
## 二、范围定义(以 P0 为准)
### 2.1 P0 必须覆盖
- 角色管理(创建/编辑/停用)
- 角色权限配置BOOLEAN/SCOPE/INTEGER
- 人员绑定角色
- 人员权限覆盖(稀疏覆盖)
- 权限快照解析与缓存失效
- 业务接口统一门禁能力
### 2.2 预留(非本期强制)
- 权限变更审批流
- 临时授权(时效权限)
- 跨租户角色模板市场
---
## 三、模块架构边界
## 3.1 模块职责(`apps/permission`
- 权限定义读取与检索
- 角色权限配置与人员绑定
- 权限快照解析、缓存、失效
- 门禁 Decorator / Mixin 输出
- 权限变更审计写入
## 3.2 核心合并规则
多角色叠加采用最宽松原则:
| 值类型 | 合并规则 |
|---|---|
| BOOLEAN | OR任一为 true 则 true |
| SCOPE | 取最大范围self < group < store < area < region < company |
| INTEGER | 取最大值,`0` 表示不限制 |
解析优先级:`个人覆盖 > 角色合并 > 默认值`
## 3.3 外部依赖
| 依赖模块 | 用途 |
|---|---|
| `apps/org` | 员工状态、组织路径、`is_system_admin` 短路 |
| `core/cache.py` | 权限快照缓存与版本控制 |
| 各业务模块 | 调用门禁函数校验权限 |
---
## 四、API 设计原则
1. PermissionDef 以只读为主,角色与覆盖可编辑。
2. 权限面板按模块分片加载,避免一次渲染超大集合。
3. 任何权限写操作后必须触发缓存失效。
4. 全部变更强制写审计(前后值、操作者、来源)。
5. API 统一结构化错误码,禁止透出内部异常栈。
---
## 五、端点清单(核心)
## 5.1 页面路由SSR
| 路径 | 方法 | 权限 code | 说明 |
|---|---|---|---|
| `/permission/roles/` | GET | `system.role.manage.allow` | 角色列表页 |
| `/permission/roles/{role_id}/` | GET | `system.role.manage.allow` | 角色详情与配置页 |
| `/permission/staff/` | GET | `system.role.manage.allow` | 人员权限列表页 |
| `/permission/staff/{staff_id}/` | GET | `system.role.manage.allow` | 人员权限详情页 |
## 5.2 HTMX 片段端点
| 路径 | 方法 | 用途 | 返回 |
|---|---|---|---|
| `/permission/fragments/role-table/` | POST | 角色筛选局刷 | HTML 片段 |
| `/permission/fragments/role-permissions/{role_id}/` | GET | 角色权限局刷 | HTML 片段 |
| `/permission/fragments/staff-permissions/{staff_id}/` | GET | 人员有效权限矩阵局刷 | HTML 片段 |
## 5.3 JSON APIP0
| 端点 | 方法 | 权限 code | 说明 |
|---|---|---|---|
| `/api/permission/defs/query/` | POST | `system.role.manage.allow` | 权限定义检索 |
| `/api/permission/roles/` | POST | `system.role.manage.allow` | 新增角色 |
| `/api/permission/roles/{id}/` | PATCH | `system.role.manage.allow` | 编辑角色 |
| `/api/permission/roles/{id}/permissions/batch-upsert/` | POST | `system.role.manage.allow` | 批量保存角色权限 |
| `/api/permission/staff/{staff_id}/roles/assign/` | POST | `system.role.manage.allow` | 人员绑定角色 |
| `/api/permission/staff/{staff_id}/overrides/batch-upsert/` | POST | `system.role.manage.allow` | 批量保存人员覆盖 |
| `/api/permission/staff/{staff_id}/effective/` | GET | `system.role.manage.allow` | 查询有效权限快照 |
| `/api/permission/cache/invalidate/` | POST | `system.role.manage.allow` | 手动失效缓存 |
---
## 六、关键 API 规范(请求/响应)
## 6.1 批量保存角色权限
`POST /api/permission/roles/{id}/permissions/batch-upsert/`
```json
{
"items": [
{"code": "property.list.view.scope", "value": {"v": "store"}},
{"code": "property.create.allow", "value": {"v": true}},
{"code": "property.owner_phone.view.daily_limit", "value": {"v": 50}}
]
}
```
## 6.2 批量保存人员覆盖
`POST /api/permission/staff/{staff_id}/overrides/batch-upsert/`
```json
{
"items": [
{"code": "property.list.view.scope", "value": {"v": "self"}},
{"code": "property.owner_phone.view.daily_limit", "value": {"v": 20}}
]
}
```
规则:
- 仅存储与角色合并值不同的条目
- 若覆盖值回到合并值,应删除覆盖记录
---
## 七、HTMX 交互约定
## 7.1 Header 约定
- 请求头:`HX-Request: true`
- 成功提示:`HX-Trigger` toast(success)
- 失败提示:`HX-Trigger` toast(error)
## 7.2 模板分片命名
- `templates/permission/fragments/role_table.html`
- `templates/permission/fragments/role_permissions_panel.html`
- `templates/permission/fragments/staff_permissions_panel.html`
---
## 八、权限与数据范围
## 8.1 门禁函数标准
- `permission_required(code)`BOOLEAN
- `scope_required(code, min_scope)`SCOPE
- `limit_required(code, required_value)`INTEGER
## 8.2 强约束
- 禁止业务模块直接查权限表自行判定
- `is_system_admin=true` 可短路,但仍需落审计
---
## 九、异步任务与缓存策略
## 9.1 异步任务(可选)
| 任务 | 触发时机 | 说明 |
|---|---|---|
| `permission_rebuild_snapshot_task` | 批量角色变更后 | 后台重建快照(大租户优化) |
## 9.2 Redis Key 规范
| Key | TTL | 说明 |
|---|---|---|
| `{schema}:perm:v{version}:staff:{staff_id}` | 1800s | 员工权限快照 |
| `{schema}:perm:version` | 永久 | 快照版本号 |
| `{schema}:perm:role:{role_id}:staff_ids` | 1800s | 角色关联员工索引 |
---
## 十、性能与可靠性约束
- 权限快照查询目标:`p95 < 30ms`(命中缓存)
- 角色保存后传播目标:`< 3s`(含缓存失效)
- 大范围权限调整采用版本号惰性失效,避免全量删 key 风暴
---
## 十一、安全与合规
1. 权限台仅授权管理员访问。
2. 每次变更必须记录前后值 JSON、操作者、IP、时间。
3. 系统预置关键角色只允许停用,不允许物理删除。
4. 不允许直接向前端暴露无权访问权限项明细。
---
## 十二、错误码建议
| code | HTTP | 场景 |
|---|---|---|
| `PERMISSION_ROLE_NOT_FOUND` | 404 | 角色不存在 |
| `PERMISSION_DEF_NOT_FOUND` | 404 | 权限项不存在 |
| `PERMISSION_VALUE_TYPE_MISMATCH` | 400 | 值类型不匹配 |
| `PERMISSION_SCOPE_INVALID` | 400 | scope 非法 |
| `PERMISSION_DENIED` | 403 | 无访问权限 |
---
## 十三、测试映射P0
| 场景 | 最低覆盖 |
|---|---|
| 多角色合并 | BOOLEAN/SCOPE/INTEGER 合并正确 |
| 个人覆盖 | 覆盖优先级正确,冗余覆盖可清理 |
| 缓存一致性 | 写后失效,读取最新快照 |
| 门禁三态 | 200 / 403 / 302 覆盖完整 |
测试文件:`tests/integration/permission/test_us_permission.py`
---
## 十四、落地顺序建议
1. 先实现 Resolver + Cache 能力
2. 再做角色与角色权限编辑
3. 再做人员绑定与覆盖配置
4. 最后统一替换业务模块门禁调用
---
## 十五、文档同步规则
- 权限数据结构变更:同步 `DATA_MODEL_PERMISSION.md`
- 新增权限 code同步 `DATA_MODEL/ENUMS.md` 与权限种子
- API 变更:同步本文件与权限 PRD 验收条目