第4章 组织架构与角色分层设计:部门层级、岗位角色、权限继承规则
4.1 边界定义
组织架构设计是审批流与权限模型的骨骼。本章聚焦于企业内部“部门—岗位—人员”三层结构如何在权限模型中映射,以及权限继承规则如何保证最小权限原则的同时降低维护成本。边界外不涉及外部组织(供应商、客户)的联邦身份,也不讨论同一个人跨部门兼职的复杂场景(将在第18章专题讨论)。
4.2 分层模型
典型的组织权限分层包含三个核心层级,每层承载不同的职责:
- 部门层级(Division/Department):组织树的节点,用于定义资源归属与审批流向的横向范围。
- 岗位角色(Position/Role):附着在部门上的抽象职能,不绑定具体人员;一个岗位可被多人担任,同一人可兼任不同岗位。
- 人员(Employee):最终操作实体,通过岗位获得权限,并通过上级部门继承父级权限。
| 层级 | 实体类型 | 权限绑定对象 | 授予方式 |
|---|---|---|---|
| 部门 | Node | 资源可见范围、审批路由规则 | 继承给子部门 |
| 岗位 | Role | 功能权限(菜单、按钮) | 直接授予或从父岗位继承 |
| 人员 | User | 数据权限(行级、字段级) | 持有岗位后自动继承 |
4.3 组件职责
权限引擎需要三个核心组件完成组织架构与角色分层:
- 组织树服务:维护部门父子关系、上下级链路的存取与缓存,支持按路径查询祖先部门。
- 角色-权限映射表:存储每个岗位角色可执行的操作列表(如“订单审批-通过”、“出库单-查看”)。
- 继承计算器:在登录或授权检查时,递归合并用户所有岗位权限,再叠加部门继承的数据范围。
设计权衡提示: 继承深度一般限制为3~5层。过浅则树形失去意义,过深则递归查询性能退化严重。建议在部门树上增加
level 字段,并在角色表增加 inherit_from_parent 布尔标记。
4.4 数据流与控制流
一次用户请求访问“销售订单审批”功能的完整依赖链路:
- 控制流:用户点击“审批”按钮 → 前端携带 userId + 订单Id → 后端功能权限拦截器。
- 数据流:权限引擎读取用户 → 通过 UserRole 中间表获取所有岗位角色 ID → 通过 RolePermission 表获取每个角色对应的操作码。
- 调用组织树服务,获取用户所属部门及其所有祖先部门 ID → 计算数据权限范围(如仅可查看本部门及下级部门的订单)。
- 若功能权限有“审批”操作码且订单部门在用户可见范围内,则放行;否则返回 403。
4.5 信任链路
信任基础建立在以下两点:
- 岗位授予必须经过部门负责人或HR系统审批,不可由用户自行绑定;
- 权限继承规则不可被低等级角色覆盖,即父部门权限始终作为上限,子部门只能追加或保留,不能缩小父级授予的数据范围。
注意: 如果允许子部门缩小父级权限,会导致数据可见性空洞(例如销售总监能看全国,但华东区经理故意关闭上海团队数据),对合规审计造成困难。建议采用“白名单叠加,不得撤销父级”策略。
4.6 选型权衡
| 方案 | 继承路径存储 | 查询性能 | 维护复杂度 | 适用场景 |
|---|---|---|---|---|
| 闭合表(Closure Table) | 另建表存所有祖-孙关系 | 单次查询O(1) | 写时需更新多条记录 | 组织树深且多级递归查询频繁 |
| 物化路径(Materialized Path) | 在部门表存完整父链 | 通过LIKE前缀索引查询 | 中等 | 树深度稳定,写少读多 |
| 嵌套集(Nested Set) | 左右值区间 | 范围查询极快 | 增删节点需重算大量记录 | 静态树,几乎不修改 |
| AD(Adjacency List) | 仅存直接父节点 | 递归查询深度大时慢 | 最简 | 小团队、树浅(<4层) |
推荐做法: 中小规模(2000人以内)使用 物化路径 + 岗位表独立记录级别;大规模建议引入图形数据库(如 Neo4j)直接按图遍历继承关系。
4.7 风险点
- 循环依赖:部门父节点误配成子节点,导致递归死循环。需在组织树服务中增加环检测(如设置最大递归深度并记录已访问节点ID)。
- 权限膨胀:继承链过长导致用户实际权限远大于预期。建议在任职表中增加
max_inheritance_level字段做上限。 - 部门合并/拆分:变更时历史审批实例的数据权限可能失效。需要保留快照或记录当时岗位归属。
4.8 落地步骤
- 定义组织树数据结构:选择物化路径或闭合表,创建 department 表,包含 id, name, parent_id, path, level。
- 岗位角色表与部门解耦:position 表只存 id, name, dept_id, inherit_from_parent(是否继承父部门权限)。
- 用户岗位置入:创建 user_position 中间表,start_date/end_date 支持临时授权。
- 实现权限继承计算器:编写递归函数或使用CTE(PostgreSQL/MySQL 8+)查询用户所有祖先部门ID。
- 测试继承边界:构造三层部门树,验证子部门岗位能否看到父部门数据;验证跨部门嵌套时不泄露。
-- PostgreSQL 示例:物化路径查询所有祖先部门ID
WITH RECURSIVE dept_tree AS (
SELECT id, parent_id, 1 AS lvl
FROM department
WHERE id = :userIdDeptId
UNION ALL
SELECT d.id, d.parent_id, dt.lvl + 1
FROM department d
INNER JOIN dept_tree dt ON d.id = dt.parent_id
)
SELECT id FROM dept_tree ORDER BY lvl DESC
-- 该查询返回从根到当前部门的所有部门ID
4.9 验收标准
| 验收项 | 操作 | 预期结果 |
|---|---|---|
| 单部门-单角色 | A部门经理岗位对部门订单有审批权限;用户X持有该岗位 | X可审批A部门及子部门订单 |
| 多岗位叠加 | 用户X同时持有A部门经理和B部门普通员工角色 | X拥有A部门及子部门的审批权限 + B部门的只读权限 |
| 继承上限限制 | 岗位设置 max_inheritance_level=2;用户所在部门深度为4 | 只能看到本部门及父两级部门数据 |
| 部门移动后 | 将C子部门从D父部门移到E父部门 | C部门及下属用户权限范围更新为E的子树(需重新计算路径) |
4.10 设计决策检查清单
- 是否已确定继承深度上限?(默认建议3层)
- 岗位表是否包含
inherit_from_parent字段以控制是否继承父部门权限? - 是否在组织树服务中实现了环检测?
- 部门合并/拆分场景是否已有历史快照方案?
- 测试用例是否覆盖“多岗位叠加”和“跨部门嵌套”?