SaaS平台的权限模型设计:从RBAC到ABAC再到ReBAC的演进复盘
2026/7/22 9:58:28 网站建设 项目流程

SaaS平台的权限模型设计:从RBAC到ABAC再到ReBAC的演进复盘

权限模型是SaaS平台的骨架。从最简单的RBAC到动态的ABAC,再到基于关系的ReBAC,每一次演进背后都是业务复杂度的真实倒逼。本文将复盘我们在权限模型上的三次架构升级,以及最终形成的混合权限引擎设计。

一、为什么权限模型需要演进?

SaaS平台的权限管理需求通常经历三个阶段:

阶段业务特征权限需求适用模型
起步期单一产品,角色固定管理员/普通用户 二分RBAC
成长期多产品线,自定义角色细粒度资源+条件控制ABAC
成熟期多租户、层级组织、资源共享跨资源关系、继承链ReBAC

大多数团队在起步期选择的RBAC会在成长期逐渐暴露出"角色爆炸"问题——每新增一种权限组合就需要创建新角色。这正是我们第一次重构的起点。

二、RBAC的局限与ABAC的引入

2.1 RBAC的"角色爆炸"困境

传统RBAC模型的数据结构:

-- 经典五表设计 CREATE TABLE t_user (id, username, ...); CREATE TABLE t_role (id, name, ...); CREATE TABLE t_permission (id, resource, action, ...); CREATE TABLE t_user_role (user_id, role_id); CREATE TABLE t_role_permission (role_id, permission_id);

当业务需要"用户只能查看自己部门的订单"或"华东区经理可以审批10万以内的报销"这类条件规则时,RBAC只能通过不断创建新角色来满足。100个条件组合就需要100个角色,维护成本失控。

2.2 ABAC:基于属性的动态策略引擎

ABAC的核心思想是将权限判断从"你有什么角色"转变为"你在什么条件下能做什么":

2.3 ABAC策略引擎的核心实现

@Data @AllArgsConstructor public class AccessRequest { private Subject subject; // 用户主体属性 private Resource resource; // 资源属性 private Action action; // 操作类型 private Environment env; // 环境上下文 } public interface PolicyRule { /** 评估规则是否匹配 */ boolean evaluate(AccessRequest request); /** 规则优先级(数字越小越优先) */ int priority(); } // 条件规则示例:订单金额小于10万且审批人在同一部门 @Component public class OrderApprovalRule implements PolicyRule { @Override public boolean evaluate(AccessRequest request) { Subject subject = request.getSubject(); Resource resource = request.getResource(); // 属性条件链 return "ORDER".equals(resource.getType()) && "APPROVE".equals(request.getAction().getName()) && resource.getAttribute("amount").asDouble() <= 100_000 && subject.getAttribute("department") .equals(resource.getAttribute("department")); } @Override public int priority() { return 10; } } @Service public class ABACPolicyEngine { private final List<PolicyRule> rules; public ABACPolicyEngine(List<PolicyRule> rules) { // 按优先级排序 this.rules = rules.stream() .sorted(Comparator.comparingInt(PolicyRule::priority)) .toList(); } /** * 评估访问请求 * 策略:首次匹配即生效(First-Applicable) */ public Decision evaluate(AccessRequest request) { for (PolicyRule rule : rules) { if (rule.evaluate(request)) { return Decision.PERMIT; } } return Decision.DENY; // 默认拒绝 } }

2.4 策略的DSL化配置

为了降低策略变更的开发成本,引入轻量级DSL:

# 订单审批策略 - 可在管理后台动态修改 policy: name: "order-approval-policy" description: "订单审批权限策略" rules: - name: "small-order-self-approval" priority: 10 condition: all: - fact: "resource.type" operator: "equals" value: "ORDER" - fact: "action.name" operator: "equals" value: "APPROVE" - fact: "resource.amount" operator: "lessThan" value: 100000 - fact: "subject.department" operator: "equals" value: "{{resource.department}}" effect: "PERMIT" - name: "large-order-director-approval" priority: 20 condition: all: - fact: "resource.type" operator: "equals" value: "ORDER" - fact: "resource.amount" operator: "greaterThan" value: 100000 - fact: "subject.level" operator: "greaterThanOrEqual" value: "P8" # 总监级别 effect: "PERMIT"

三、ReBAC:基于关系图的权限模型

3.1 当ABAC也不够用时

在以下场景中,ABAC也显得力不从心:

  • "用户A共享了文档D给用户B,B又可以再共享给C"(传递关系)
  • "父组织的管理员自动拥有子组织的数据访问权限"(继承关系)
  • "项目成员可以看到同项目其他人的任务"(同组关系)

这些场景的核心特征是权限依赖于实体间的关系,而这正是Google Zanzibar论文中提出的ReBAC(Relationship-Based Access Control)要解决的问题。

3.2 基于图模型的关系存储

3.3 ReBAC的核心实现

@Service public class ReBACEngine { private final Neo4jTemplate neo4j; private final LoadingCache<String, Set<String>> permissionCache; /** * 检查两个实体之间是否存在指定关系 * 支持关系传递推导 */ public boolean checkRelation(String subjectId, String relation, String objectId) { String cacheKey = subjectId + ":" + relation + ":" + objectId; return permissionCache.get(cacheKey, key -> { // Cypher查询:支持多跳关系传递 String cypher = """ MATCH (s:Entity {id: $subjectId}) MATCH (o:Entity {id: $objectId}) MATCH path = shortestPath((s)-[*1..5]-(o)) WHERE ALL(r IN relationships(path) WHERE r.type IN ['member', 'parent', 'owner', 'viewer', 'editor']) RETURN path """; var result = neo4j.query(cypher) .bind("subjectId", subjectId) .bind("objectId", objectId) .fetch(); return result.isPresent(); }); } /** * 创建关系 */ public void createRelation(String subjectId, String relation, String objectId) { String cypher = """ MERGE (s:Entity {id: $subjectId}) MERGE (o:Entity {id: $objectId}) CREATE (s)-[:%s]->(o) """.formatted(relation.toUpperCase()); neo4j.query(cypher) .bind("subjectId", subjectId) .bind("objectId", objectId) .run(); // 关系变更后清除相关缓存 permissionCache.invalidateAll(); } }

四、三种模型的混合使用与迁移策略

4.1 混合权限引擎架构

@Service public class HybridPermissionEngine { private final RBACService rbacService; private final ABACPolicyEngine abacEngine; private final ReBACEngine rebacEngine; /** * 统一权限检查入口 * 决策链:RBAC → ABAC → ReBAC,任一PERMIT即通过 */ public Decision check(AccessRequest request) { // L1: RBAC快速通道(低延迟,适用于简单场景) Decision rbacResult = rbacService.check( request.getSubject().getId(), request.getResource().getType(), request.getAction().getName() ); if (rbacResult == Decision.PERMIT) { return Decision.PERMIT; } // L2: ABAC策略评估(适用于条件规则) Decision abacResult = abacEngine.evaluate(request); if (abacResult == Decision.PERMIT) { return Decision.PERMIT; } // L3: ReBAC关系检查(适用于关系依赖场景) if (request.getResource().hasRelationRequired()) { Decision rebacResult = rebacEngine.checkRelation( request.getSubject().getId(), request.getRequiredRelation(), request.getResource().getId() ); if (rebacResult == Decision.PERMIT) { return Decision.PERMIT; } } return Decision.DENY; } }

4.2 渐进式迁移路线

迁移过程中的核心原则:

@Configuration public class PermissionMigrationConfig { @Bean public FeatureFlag permissionModelFlag() { return FeatureFlag.builder() .key("permission.model.migration") .description("权限模型迁移灰度开关") // 租户级灰度:白名单租户先切换 .rolloutStrategy(new TenantBasedRollout( Set.of("tenant-pilot-1", "tenant-pilot-2"), // 灰度租户 0.1 // 后续10%流量 )) .fallback(() -> Decision.PERMIT) // 降级策略:异常时放行 .build(); } }
迁移维度策略
数据迁移双写模式:新权限同时写入RBAC和ABAC表,异步校验一致性
灰度策略租户级灰度 → 百分比灰度 → 全量切换
回滚方案保留RBAC数据作为降级基线,开关可秒级回滚
验证手段双轨运行期间对比新老引擎结果,差异告警

五、总结

权限模型的选择不是非此即彼的技术决策,而是随业务复杂度演进的工程实践:

  1. RBAC阶段:团队小于20人、角色类型少于10种时,RBAC足够简单可靠。
  2. ABAC阶段:当权限规则开始依赖"条件"而非"角色"时,引入策略引擎。DSL化是关键——让非技术人员也能配置规则。
  3. ReBAC阶段:当权限判断依赖"关系拓扑"时(共享、继承、传递),图存储是必然选择。
  4. 混合架构:三层决策链(RBAC→ABAC→ReBAC)既保证了简单场景的低延迟,也覆盖了复杂场景的灵活性。

核心经验:不要一步到位设计完美权限模型,而是让模型随业务一起生长。每一次演进都是在解决上一阶段的真实瓶颈。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询