企业级权限系统怎么设计一 —— 优秀领域模型的价值
在设计企业级权限系统时,领域模型是理解业务逻辑的核心工具。一个清晰、合理的领域模型,能帮助我们准确刻画业务中的关键角色和关系,避免早期架构陷阱,也能为后续的扩展和维护打下良好基础。
本文以权限系统为例,通过逐步拆解业务需求,构建并优化领域模型,并展现领域模型在系统设计中的实战价值。
需求
较复杂的权限系统需求,涉及客户、用户、账户、角色、功能等:
- 一个客户可以创建多个用户;
- 客户名下可以开通多个账户,也可以申请多个功能(如转账、查询等);
- 用户可以绑定多个账户,并被授予一个或多个角色;
- 角色控制用户可以使用哪些功能;
- 功能使用往往依赖于账户权限,比如某个功能要求“账户支持 + 用户具备角色权限 + 用户关联该账户”才可执行;
- 有些功能还涉及更细的权限控制,例如区分“经办、复核、查询”等操作角色。
第一步:标准 RBAC 模型
首先,我们先实现需求中的客户、用户、角色、功能部分 RBAC(基于角色的访问控制)是最常见的权限管理模型。它通过“角色”这一中间层,把用户与功能权限解耦,降低直接授权的复杂性。
基于业务规则,我们在建模时遵循以下逻辑:
- 客户先开通功能:客户必须先在系统中启用某个功能,才允许其角色引用;
- 角色绑定功能:角色由客户定义,并在其开通的功能范围内,配置可以使用的功能;
- 用户绑定角色:用户通过绑定角色,间接获得对功能的使用权限。
对应的领域模型如下(简化版):
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 : "关联"
第二步:加入账户
接下来,我们完成需求中关于账号的问题。如:
- 用户可能管理多个账户;
- 不同账户支持的功能可能不同;
- 功能使用往往依赖于账户权限,比如某个功能要求“账户支持 + 用户具备角色权限 + 用户关联该账户”才可执行。
此时,我们需要在模型中引入“账户”这一关键实体,并处理好以下几点:
- 用户-账户绑定:一个用户可以绑定多个账户;
- 局部权限削减:允许对特定账户进行权限细化控制(如关闭某功能的复核权限);
于是,我们将模型进一步扩展,加入账户和账户功能权限:
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 模型出发,逐步引入账户、细粒度权限控制、审批等复杂场景,最终通过“分离审批模块”的方式控制了模型复杂度,让系统更具可维护性与可扩展性。
领域模型的真正价值在于:
- 帮助我们梳理清楚系统中“谁是关键角色”、“有哪些关键行为”和“这些行为间有什么约束”;
- 提前暴露潜在的设计风险和耦合问题;
- 为后续的技术演进和模块扩展提供坚实基础。