第4章 组织架构与角色分层设计:部门层级、岗位角色、权限继承规则

4.1 边界定义

组织架构设计是审批流与权限模型的骨骼。本章聚焦于企业内部“部门—岗位—人员”三层结构如何在权限模型中映射,以及权限继承规则如何保证最小权限原则的同时降低维护成本。边界外不涉及外部组织(供应商、客户)的联邦身份,也不讨论同一个人跨部门兼职的复杂场景(将在第18章专题讨论)。

4.2 分层模型

典型的组织权限分层包含三个核心层级,每层承载不同的职责:

  • 部门层级(Division/Department):组织树的节点,用于定义资源归属与审批流向的横向范围。
  • 岗位角色(Position/Role):附着在部门上的抽象职能,不绑定具体人员;一个岗位可被多人担任,同一人可兼任不同岗位。
  • 人员(Employee):最终操作实体,通过岗位获得权限,并通过上级部门继承父级权限。
层级实体类型权限绑定对象授予方式
部门Node资源可见范围、审批路由规则继承给子部门
岗位Role功能权限(菜单、按钮)直接授予或从父岗位继承
人员User数据权限(行级、字段级)持有岗位后自动继承

4.3 组件职责

权限引擎需要三个核心组件完成组织架构与角色分层:

  • 组织树服务:维护部门父子关系、上下级链路的存取与缓存,支持按路径查询祖先部门。
  • 角色-权限映射表:存储每个岗位角色可执行的操作列表(如“订单审批-通过”、“出库单-查看”)。
  • 继承计算器:在登录或授权检查时,递归合并用户所有岗位权限,再叠加部门继承的数据范围。
设计权衡提示: 继承深度一般限制为3~5层。过浅则树形失去意义,过深则递归查询性能退化严重。建议在部门树上增加 level 字段,并在角色表增加 inherit_from_parent 布尔标记。

4.4 数据流与控制流

一次用户请求访问“销售订单审批”功能的完整依赖链路:

  1. 控制流:用户点击“审批”按钮 → 前端携带 userId + 订单Id → 后端功能权限拦截器。
  2. 数据流:权限引擎读取用户 → 通过 UserRole 中间表获取所有岗位角色 ID → 通过 RolePermission 表获取每个角色对应的操作码。
  3. 调用组织树服务,获取用户所属部门及其所有祖先部门 ID → 计算数据权限范围(如仅可查看本部门及下级部门的订单)。
  4. 若功能权限有“审批”操作码且订单部门在用户可见范围内,则放行;否则返回 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 落地步骤

  1. 定义组织树数据结构:选择物化路径或闭合表,创建 department 表,包含 id, name, parent_id, path, level。
  2. 岗位角色表与部门解耦:position 表只存 id, name, dept_id, inherit_from_parent(是否继承父部门权限)。
  3. 用户岗位置入:创建 user_position 中间表,start_date/end_date 支持临时授权。
  4. 实现权限继承计算器:编写递归函数或使用CTE(PostgreSQL/MySQL 8+)查询用户所有祖先部门ID。
  5. 测试继承边界:构造三层部门树,验证子部门岗位能否看到父部门数据;验证跨部门嵌套时不泄露。
-- 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的子树(需重新计算路径)
组织架构与角色分层·权限继承示意图 集团总部·根部门 销售中心 研发中心 华东销售部 华南销售部 岗位:销售总监 岗位:区域销售经理 岗位:普通销售员 人员A 人员B 虚线:权限继承 实线:岗位授予 部门节点 岗位角色

4.10 设计决策检查清单

  • 是否已确定继承深度上限?(默认建议3层)
  • 岗位表是否包含 inherit_from_parent 字段以控制是否继承父部门权限?
  • 是否在组织树服务中实现了环检测?
  • 部门合并/拆分场景是否已有历史快照方案?
  • 测试用例是否覆盖“多岗位叠加”和“跨部门嵌套”?