企业级权限系统怎么设计一 —— 优秀领域模型的价值

28 阅读5分钟

企业级权限系统怎么设计一 —— 优秀领域模型的价值

在设计企业级权限系统时,领域模型是理解业务逻辑的核心工具。一个清晰、合理的领域模型,能帮助我们准确刻画业务中的关键角色和关系,避免早期架构陷阱,也能为后续的扩展和维护打下良好基础。

本文以权限系统为例,通过逐步拆解业务需求,构建并优化领域模型,并展现领域模型在系统设计中的实战价值。


需求

较复杂的权限系统需求,涉及客户、用户、账户、角色、功能等:

  • 一个客户可以创建多个用户;
  • 客户名下可以开通多个账户,也可以申请多个功能(如转账、查询等);
  • 用户可以绑定多个账户,并被授予一个或多个角色;
  • 角色控制用户可以使用哪些功能;
  • 功能使用往往依赖于账户权限,比如某个功能要求“账户支持 + 用户具备角色权限 + 用户关联该账户”才可执行;
  • 有些功能还涉及更细的权限控制,例如区分“经办、复核、查询”等操作角色。

第一步:标准 RBAC 模型

首先,我们先实现需求中的客户、用户、角色、功能部分 RBAC(基于角色的访问控制)是最常见的权限管理模型。它通过“角色”这一中间层,把用户与功能权限解耦,降低直接授权的复杂性。

基于业务规则,我们在建模时遵循以下逻辑:

  1. 客户先开通功能:客户必须先在系统中启用某个功能,才允许其角色引用;
  2. 角色绑定功能:角色由客户定义,并在其开通的功能范围内,配置可以使用的功能;
  3. 用户绑定角色:用户通过绑定角色,间接获得对功能的使用权限。

对应的领域模型如下(简化版):

erDiagram
    CUSTOMER ||--o{ USER : "创建"
    CUSTOMER ||--o{ ROLE : "拥有"
    CUSTOMER ||--o{ CUSTOMER_FUNCTION : "开通功能"

    USER ||--o{ USER_ROLE : ""

    ROLE ||--o{ USER_ROLE : ""
    ROLE ||--o{ ROLE_FUNCTION: "定义"

    FUNCTION ||--o{ ROLE_FUNCTION : "关联"
    FUNCTION ||--o{ CUSTOMER_FUNCTION : "关联"

第二步:加入账户

接下来,我们完成需求中关于账号的问题。如:

  • 用户可能管理多个账户;
  • 不同账户支持的功能可能不同;
  • 功能使用往往依赖于账户权限,比如某个功能要求“账户支持 + 用户具备角色权限 + 用户关联该账户”才可执行。

此时,我们需要在模型中引入“账户”这一关键实体,并处理好以下几点:

  1. 用户-账户绑定:一个用户可以绑定多个账户;
  2. 局部权限削减:允许对特定账户进行权限细化控制(如关闭某功能的复核权限);

于是,我们将模型进一步扩展,加入账户和账户功能权限:

erDiagram
    CUSTOMER ||--o{ USER : "创建"
    CUSTOMER ||--o{ ACCOUNT : "上挂"
    CUSTOMER ||--o{ ROLE : "拥有"
    CUSTOMER ||--o{ CUSTOMER_FUNCTION : "开通功能"

    USER ||--o{ USER_ROLE : ""
    USER ||--o{ USER_ACCOUNT : ""

    ROLE ||--o{ USER_ROLE : ""
    ROLE ||--o{ ROLE_FUNCTION : "定义"

    FUNCTION ||--o{ ROLE_FUNCTION : "关联"
    FUNCTION ||--o{ ACCOUNT_FUNCTION : ""
    FUNCTION ||--o{ CUSTOMER_FUNCTION : ""

    ACCOUNT ||--o{ USER_ACCOUNT : ""
    USER_ACCOUNT ||--o{ ACCOUNT_FUNCTION : ""

第三步:补充细粒度权限控制:经办 / 复核 / 查询

接下来,我们补充上需求中对权限的细粒度控制:

  • 某用户只能经办+查询或者复核+查询或仅查询

此时,仅靠“是否拥有功能”已不足以表达授权语义,我们需要在模型中引入操作维度的控制。于是,我们在角色功能和账户功能授权中,分别加入操作级别的标志位(如 can_execute、can_review、can_view)【这样设计好么,我们在下一篇中详细讨论】:

erDiagram
    %% 客户实体
    CUSTOMER {
        int id PK "客户ID"
        string name "客户名称"
    }

    %% 用户实体
    USER {
        int id PK "用户ID"
        int customer_id FK "所属客户ID"
        string username "用户名"
        string password "密码"
    }

    %% 账户实体
    ACCOUNT {
        int id PK "账户ID"
        int customer_id FK "所属客户ID"
        string account_number "账户编号"
    }

    %% 角色实体
    ROLE {
        int id PK "角色ID"
        int customer_id FK "所属客户ID"
        string name "角色名称"
    }

    %% 客户功能实体
    CUSTOMER_FUNCTION {
        int id PK "客户功能ID"
        int customer_id FK "所属客户ID"
        int function_id FK "功能ID"
    }

    %% 功能实体
    FUNCTION {
        int id PK "功能ID"
        string name "功能名称"
        boolean approval_required "是否需要审批"
        string function_type "功能类型:基础管理/业务功能"
    }

    %% 角色功能权限(细化操作权限)
    ROLE_FUNCTION {
        int id PK "权限ID"
        int role_id FK "所属角色ID"
        int function_id FK "功能ID"
        boolean can_execute "经办权限"
        boolean can_review "复核权限"
        boolean can_view "查询权限"
        int approval_level "审批级别"
    }

    %% 用户-角色中间表
    USER_ROLE {
        int user_id FK "用户ID"
        int role_id FK "角色ID"
    }

    %% 用户-账户中间表
    USER_ACCOUNT {
        int user_id FK "用户ID"
        int account_id FK "账户ID"
    }

    %% 账户功能权限(细化操作权限)
    USER_ACCOUNT_FUNCTION {
        int id PK "账户功能权限ID"
        int user_id FK "用户ID"
        int account_id FK "账户ID"
        int function_id FK "功能ID"
        boolean can_execute "经办权限"
        boolean can_review "复核权限"
        boolean can_view "查询权限"
    }

    %% 实体关系定义
    CUSTOMER ||--o{ USER : "创建"
    CUSTOMER ||--o{ ACCOUNT : "上挂"
    CUSTOMER ||--o{ ROLE : "拥有"
    CUSTOMER ||--o{ CUSTOMER_FUNCTION : "开通功能"

    USER ||--o{ USER_ROLE : ""
    USER ||--o{ USER_ACCOUNT : ""

    ROLE ||--o{ USER_ROLE : ""
    ROLE ||--o{ ROLE_FUNCTION : "定义"

    FUNCTION ||--o{ ROLE_FUNCTION : "关联"
    FUNCTION ||--o{ USER_ACCOUNT_FUNCTION : ""
    FUNCTION ||--o{ CUSTOMER_FUNCTION : ""

    ACCOUNT ||--o{ USER_ACCOUNT : ""
    USER_ACCOUNT ||--o{ USER_ACCOUNT_FUNCTION : ""

局限:需求扩展,模型开始暴露问题

现在模型似乎还是清晰的,随着审批相关权限(上述权限的细粒度控制)的引入

新增的需求:

  • 对应审批权限的审批级别,即用户可以在哪个级别审批

我们可以在用户模型增加审批级别字段

又有新的需求:

  • 不同人在不同功能有不同的级别

越来越复杂了,不过现在已经能明显看出来,这些属于审批领域的需求。此时原本清晰的权限模型开始被侵蚀:

  • 在多个权限表中加入审批相关字段;
  • 逻辑变得复杂,耦合度上升;
  • 模型职责模糊,理解困难。

这意味着,是时候分离审批逻辑了。


更好的设计:拆分审批领域

为了解决上述问题,我们可以将审批模块从原有权限模型中剥离出来,单独设计一个独立的审批子系统(同业的做法)。

可行方案

  • 使用工作流引擎:适用于复杂多级审批场景;
  • 自定义审批配置模块:绑定功能、账户、金额等维度,定义经办人、复核人、审批规则。

这样做的好处包括:

1. 职责清晰

  • 原有权限模型专注于定义“谁可以做什么”;
  • 审批模块专注于定义“哪些操作需要审批,由谁来批、批几级”。

2. 降低复杂度

  • 不再需要在账户权限或角色权限表中混入审批级别等字段;
  • 审批流程以配置驱动,逻辑独立,模型更简洁。

3. 提升灵活性

  • 审批规则支持按功能、账户、金额、用户类型等灵活配置;
  • 多级审批、会签、串签等复杂流程可动态组合,无需改动权限模型。

总结:领域模型的真正价值

一个优秀的领域模型,并不是一开始就设计得多么“完美”,而在于始终服务于业务规则的清晰表达与系统的长期演进

本案例中,我们从一个标准的 RBAC 模型出发,逐步引入账户、细粒度权限控制、审批等复杂场景,最终通过“分离审批模块”的方式控制了模型复杂度,让系统更具可维护性与可扩展性。

领域模型的真正价值在于:

  • 帮助我们梳理清楚系统中“谁是关键角色”、“有哪些关键行为”和“这些行为间有什么约束”;
  • 提前暴露潜在的设计风险和耦合问题;
  • 为后续的技术演进和模块扩展提供坚实基础。