270 lines
8.0 KiB
Markdown
270 lines
8.0 KiB
Markdown
> **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 API(P0)
|
||
|
||
| 端点 | 方法 | 权限 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 验收条目
|