7.8 KiB
7.8 KiB
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
一、文档定位与边界
本文件仅定义权限模块的:
- RBAC + 个人覆盖架构边界
- 权限解析/合并与门禁约束
- API 端点设计(页面 / HTMX / JSON)
- 缓存一致性与审计策略
- 错误码与测试映射
不在本文件展开权限相关表字段与索引。数据结构以
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 设计原则
- PermissionDef 以只读为主,角色与覆盖可编辑。
- 权限面板按模块分片加载,避免一次渲染超大集合。
- 任何权限写操作后必须触发缓存失效。
- 全部变更强制写审计(前后值、操作者、来源)。
- 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/
{
"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/
{
"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-Triggertoast(success) - 失败提示:
HX-Triggertoast(error)
7.2 模板分片命名
templates/permission/fragments/role_table.htmltemplates/permission/fragments/role_permissions_panel.htmltemplates/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 风暴
十一、安全与合规
- 权限台仅授权管理员访问。
- 每次变更必须记录前后值 JSON、操作者、IP、时间。
- 系统预置关键角色只允许停用,不允许物理删除。
- 不允许直接向前端暴露无权访问权限项明细。
十二、错误码建议
| 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
十四、落地顺序建议
- 先实现 Resolver + Cache 能力
- 再做角色与角色权限编辑
- 再做人员绑定与覆盖配置
- 最后统一替换业务模块门禁调用
十五、文档同步规则
- 权限数据结构变更:同步
DATA_MODEL_PERMISSION.md - 新增权限 code:同步
DATA_MODEL/ENUMS.md与权限种子 - API 变更:同步本文件与权限 PRD 验收条目