从 RBAC 到 OpenFGA:细粒度授权的架构、落地与取舍
Posted on Thu 05 March 2026 in Tech • 8 min read
| Abstract | 从 RBAC 到 OpenFGA:细粒度授权的架构、落地与取舍 |
|---|---|
| Authors | Walter Fan |
| Category | tech note |
| Status | v1.0 |
| Updated | 2026-03-05 |
| License | CC-BY-NC-ND 4.0 |
从 RBAC 到 OpenFGA:细粒度授权的架构、落地与取舍
写了二十多年代码,我越来越觉得:认证(Authentication)是一道门,授权(Authorization)是一栋楼里的每一把锁。门只需要装一道,但锁要一间一间配,漏一间就是安全事故。
RBAC(Role-Based Access Control)是这栋楼里最常见的锁——简单、标准、够用。但当你的楼从一栋变成一个园区,从固定住户变成随时来去的访客,RBAC 就开始吃力了。
这篇文章从 RBAC 的局限出发,聊聊 OpenFGA 这把"新锁"——它的架构设计、落地路径、以及商业公司在"用开源"还是"自己造"之间的取舍。
一、RBAC:老黄牛的能力边界
1.1 RBAC 的核心模型
RBAC 的思路很直白:用户 → 角色 → 权限。
User ──── Role ──── Permission
│
Action × Resource
一个典型的 RBAC 表结构:
-- 用户-角色关联
CREATE TABLE user_roles (
user_id BIGINT NOT NULL,
role_id BIGINT NOT NULL,
PRIMARY KEY (user_id, role_id)
);
-- 角色-权限关联
CREATE TABLE role_permissions (
role_id BIGINT NOT NULL,
permission_id BIGINT NOT NULL,
PRIMARY KEY (role_id, permission_id)
);
-- 权限定义
CREATE TABLE permissions (
id BIGINT PRIMARY KEY,
action VARCHAR(50), -- read, write, delete
resource VARCHAR(100) -- document, order, user
);
RBAC 的优势很明显:
- 概念简单:产品经理、运维、审计都能理解
- 实现成熟:Spring Security、Django Permission、Casbin 都有现成支持
- 审计友好:谁有什么角色、角色有什么权限,一目了然
- NIST 标准:RBAC 有 NIST INCITS 359-2004 标准,合规友好
1.2 RBAC 的三个痛点
但当系统复杂到一定程度,RBAC 的三个痛点就会暴露:
痛点一:角色爆炸(Role Explosion)
假设你有一个文档管理系统,需要控制:
- 3 个部门(工程、产品、市场)
- 4 种操作(查看、编辑、评论、删除)
- 2 个数据范围(本部门、全公司)
纯 RBAC 需要 3 × 4 × 2 = 24 个角色。再加上项目维度、层级维度,角色数量指数增长。我见过一个企业系统有 800+ 个角色,没人说得清每个角色到底能干什么。
痛点二:无法表达资源间的关系
RBAC 回答的是"Alice 有 editor 角色",但回答不了"Alice 是 这个文件夹 的 editor,所以她也能编辑 文件夹里的文档"。
这种层级继承(Hierarchical Inheritance)在 Google Drive、GitHub、Notion 等产品中无处不在,但 RBAC 天然不支持。你要么在业务代码里硬编码继承逻辑,要么给每个资源单独分配角色——两种方案都很痛苦。
痛点三:动态共享难以建模
"Alice 把文档分享给 Bob,Bob 可以查看但不能编辑"——这是一个 实例级别 的权限,不是角色能覆盖的。RBAC 要实现这个,通常需要引入 ACL(Access Control List),但 ACL 和 RBAC 混用会让系统变得很难维护。
RBAC 能回答的问题:
✅ Alice 是管理员吗?
✅ 管理员能删除用户吗?
RBAC 回答不了的问题:
❌ Alice 能编辑 **这个** 文档吗?(实例级)
❌ Alice 是这个文件夹的 editor,她能编辑文件夹里的文档吗?(继承)
❌ Bob 被 Alice 分享了这个文档,他能查看吗?(动态共享)
二、Google Zanzibar:巨人的答案
2019 年,Google 发表了 Zanzibar 论文,揭示了 Google Drive、YouTube、Google Cloud 等产品背后的统一授权系统。
Zanzibar 的核心思想只有一个:一切权限都是关系(Relationship)。
传统 RBAC:
User → Role → Permission → Resource
Zanzibar / ReBAC:
Subject ──relation──▶ Object
(谁) (什么关系) (什么东西)
一条关系元组(Relationship Tuple)长这样:
document:readme#editor@user:alice
翻译成人话:Alice 是 readme 文档的 editor。
这种模型的威力在于:关系可以 组合和继承。
# Alice 是 engineering 文件夹的 editor
folder:engineering#editor@user:alice
# readme 文档在 engineering 文件夹里
document:readme#parent@folder:engineering
# 授权模型定义:文档的 editor 包括其父文件夹的 editor
type document
relations
define parent: [folder]
define editor: [user] or editor from parent
现在问"Alice 能编辑 readme 吗?",Zanzibar 会沿着关系图遍历:
Alice ──editor──▶ folder:engineering
│
parent of
│
▼
document:readme
结论:Alice 是 readme 的 editor ✅
这就是 ReBAC(Relationship-Based Access Control) 的核心——权限不是静态分配的,而是通过关系图动态推导的。
三、OpenFGA 架构深度剖析
OpenFGA 是 Auth0/Okta 开源的 Zanzibar 实现,现为 CNCF Sandbox 项目。已被 Grafana Labs、Canonical(Ubuntu)、Docker、Agicap、Read.AI 等公司采用。
3.1 整体架构
┌─────────────────────────────────────────────────────────┐
│ 应用层 │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Service A │ │ Service B │ │ Service C │ │
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌──────────────────────────────────────────┐ │
│ │ OpenFGA SDK (gRPC/HTTP) │ │
│ └────────────────────┬─────────────────────┘ │
└───────────────────────┼─────────────────────────────────┘
│
▼
┌───────────────────────────────────────────────────────────┐
│ OpenFGA Server │
│ │
│ ┌─────────────┐ ┌──────────────┐ ┌─────────────────┐ │
│ │ API Layer │ │ Query Engine │ │ Change Tracker │ │
│ │ (HTTP/gRPC) │ │ (图遍历) │ │ (变更日志) │ │
│ └──────┬──────┘ └──────┬───────┘ └────────┬────────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌──────────────────────────────────────────────────┐ │
│ │ Storage Adapter │ │
│ │ PostgreSQL │ MySQL │ SQLite(beta) │ In-Memory │ │
│ └──────────────────────────────────────────────────┘ │
└───────────────────────────────────────────────────────────┘
3.2 核心概念
| 概念 | 说明 | 示例 |
|---|---|---|
| Store | 隔离的授权数据空间,类似数据库 | 每个租户一个 Store |
| Authorization Model | 定义类型、关系和权限推导规则 | DSL 文件 |
| Type | 实体类型 | user, document, folder |
| Relation | 类型之间的命名关系 | editor, viewer, parent |
| Tuple | 具体的关系实例 | document:readme#editor@user:alice |
| Condition | 基于上下文的条件约束(ABAC 能力) | ipAddress in allowedRange |
3.3 核心 API
OpenFGA 只有 6 个核心 API,设计极其克制:
┌─────────────────────────────────────────────────────┐
│ OpenFGA API │
├─────────────────────────────────────────────────────┤
│ │
│ 写入类: │
│ Write() - 写入/删除关系元组 │
│ WriteModel() - 更新授权模型 │
│ │
│ 查询类: │
│ Check() - 检查某用户是否有某权限 → bool │
│ ListObjects() - 列出用户有权访问的所有对象 │
│ ListUsers() - 列出对某对象有权限的所有用户 │
│ Expand() - 展开权限的推导路径(调试用) │
│ │
│ 管理类: │
│ CreateStore() - 创建 Store │
│ ReadChanges() - 读取变更日志(审计/同步) │
│ │
└─────────────────────────────────────────────────────┘
其中最关键的是 Check() — 它是所有授权决策的入口:
from openfga_sdk import OpenFgaClient, ClientConfiguration
from openfga_sdk.client.models import ClientCheckRequest
config = ClientConfiguration(
api_url="http://localhost:8080",
store_id="your-store-id",
authorization_model_id="your-model-id"
)
async with OpenFgaClient(config) as client:
response = await client.check(ClientCheckRequest(
user="user:alice",
relation="editor",
object="document:readme"
))
print(response.allowed) # True or False
3.4 授权模型 DSL
OpenFGA 的 DSL 是其最精妙的设计。一个 Google Drive 风格的模型:
model
schema 1.1
type user
type organization
relations
define admin: [user]
define member: [user] or admin
type folder
relations
define org: [organization]
define owner: [user]
define editor: [user] or owner or admin from org
define viewer: [user] or editor or member from org
type document
relations
define parent: [folder]
define owner: [user]
define editor: [user] or owner or editor from parent
define viewer: [user] or editor or viewer from parent
define can_share: owner
define blocked: [user]
define can_view: viewer but not blocked
define can_edit: editor but not blocked
这个模型表达了:
- 组织层级:admin 自动是 member
- 文件夹权限:org 的 admin 自动是文件夹的 editor
- 文档继承:文档继承父文件夹的权限
- 显式拒绝:被 blocked 的用户即使有其他权限也无法访问
- 分享控制:只有 owner 能分享文档
3.5 图遍历引擎
Check() 的核心是一个 有向图遍历 算法。当你问"Alice 能编辑 document:readme 吗?",引擎会:
1. 查找 document:readme 的 editor 关系定义
→ editor: [user] or owner or editor from parent
2. 分支搜索:
├── 直接关系:有没有 document:readme#editor@user:alice 元组?
├── owner 关系:Alice 是 readme 的 owner 吗?
└── 继承关系:readme 的 parent folder 的 editor 包含 Alice 吗?
├── 查找 document:readme#parent@folder:* 元组
│ → 找到 folder:engineering
└── 递归检查 folder:engineering#editor@user:alice
├── 直接关系?
├── owner 关系?
└── org admin 关系?
→ 继续遍历...
3. 任一分支返回 true → 最终结果 true
这个遍历有几个关键优化:
- 并发遍历:多个分支并行检查,任一成功即短路返回
- 缓存:热点元组和中间结果缓存
- 深度限制:防止无限递归(默认最大深度 25)
- 超时控制:单次 Check 有超时限制
四、RBAC vs ReBAC:不是替代,是演进
很多人问:用了 OpenFGA 是不是就不需要 RBAC 了?不是。
┌──────────────────────────────────────────────────────────┐
│ 授权模型演进 │
│ │
│ ACL ──▶ RBAC ──▶ ABAC ──▶ ReBAC │
│ (列表) (角色) (属性) (关系) │
│ │
│ 简单 ◀──────────────────────────────────────▶ 灵活 │
│ 粗粒度 ◀────────────────────────────────────▶ 细粒度 │
└──────────────────────────────────────────────────────────┘
| 维度 | RBAC | ReBAC (OpenFGA) |
|---|---|---|
| 核心抽象 | 角色 | 关系 |
| 粒度 | 资源类型级 | 资源实例级 |
| 继承 | 角色继承(有限) | 关系图遍历(灵活) |
| 动态共享 | 需要额外 ACL | 原生支持 |
| 性能 | O(1) 查表 | O(n) 图遍历 |
| 复杂度 | 低 | 中高 |
| 适用场景 | 后台管理、API 网关 | 文档协作、多租户 SaaS |
| 学习曲线 | 低 | 中 |
我的建议:大多数系统应该 RBAC + ReBAC 混合使用:
- 粗粒度(API 级别):用 RBAC。"只有 admin 能访问 /admin/* 接口"——简单直接。
- 细粒度(资源级别):用 ReBAC。"Alice 能编辑这个文档吗?"——需要关系推导。
# 两层授权的伪代码
@app.route("/api/documents/<doc_id>", methods=["PUT"])
@require_role("editor") # 第一层:RBAC,粗粒度
async def update_document(doc_id):
# 第二层:ReBAC,细粒度
allowed = await fga_client.check(
user=f"user:{current_user.id}",
relation="editor",
object=f"document:{doc_id}"
)
if not allowed:
return {"error": "Forbidden"}, 403
# ... 业务逻辑
五、商业公司落地路径
5.1 渐进式迁移策略
不要试图一步到位。我建议分四个阶段:
Phase 1 Phase 2 Phase 3 Phase 4
评估与 PoC 影子模式 逐步切换 全面迁移
(2-4 周) (4-8 周) (8-16 周) (持续)
│ │ │ │
▼ ▼ ▼ ▼
┌────────┐ ┌────────────┐ ┌────────────┐ ┌──────────┐
│建模 │ │双写双读 │ │新功能用 FGA │ │旧功能迁移 │
│原型验证 │ │对比结果 │ │旧功能保持 │ │下线旧系统 │
│性能测试 │ │不影响线上 │ │逐步切换 │ │ │
└────────┘ └────────────┘ └────────────┘ └──────────┘
Phase 1:评估与 PoC(2-4 周)
- 梳理现有权限模型,识别 RBAC 覆盖不了的场景
- 用 OpenFGA Playground 建模,验证能否表达业务需求
- 做性能基准测试:Check() 延迟、Write() 吞吐量
Phase 2:影子模式(4-8 周)
这是最关键的一步。在不影响线上的前提下验证正确性:
async def check_permission(user, action, resource):
# 旧系统做决策(线上生效)
old_result = rbac_check(user, action, resource)
# 新系统做决策(仅记录,不生效)
new_result = await fga_check(user, action, resource)
# 对比结果
if old_result != new_result:
logger.warning(f"Authorization mismatch: "
f"user={user}, action={action}, resource={resource}, "
f"old={old_result}, new={new_result}")
metrics.increment("authz.mismatch")
return old_result # 仍然用旧系统的结果
Phase 3:逐步切换(8-16 周)
- 新功能直接用 OpenFGA
- 旧功能按模块逐步切换,每次切换一个模块
- 保留回滚开关(Feature Flag)
Phase 4:全面迁移(持续)
- 下线旧的 RBAC 表和代码
- 建立授权模型的 CI/CD 流程
- 完善监控和告警
5.2 数据同步:最容易踩的坑
OpenFGA 的关系元组需要和业务数据保持一致。这是落地中 最容易出问题 的地方。
业务事件 OpenFGA 操作
───────── ──────────────
用户加入团队 ──────▶ Write(team:X#member@user:alice)
用户离开团队 ──────▶ Delete(team:X#member@user:alice)
文档移动到新文件夹 ──────▶ Delete(doc:Y#parent@folder:old)
Write(doc:Y#parent@folder:new)
文档被删除 ──────▶ Delete(doc:Y 相关的所有元组)
三种同步方案:
| 方案 | 一致性 | 复杂度 | 适用场景 |
|---|---|---|---|
| 同步写入(业务操作和 FGA 写入在同一事务) | 强一致 | 高(分布式事务) | 金融、医疗 |
| 事件驱动(业务写 DB → 发事件 → Consumer 写 FGA) | 最终一致 | 中 | 大多数场景 |
| 定时全量同步(定期从业务 DB 全量导入 FGA) | 弱一致 | 低 | PoC、非关键场景 |
我推荐大多数公司用 事件驱动 方案,配合幂等写入和补偿机制:
# Kafka Consumer 示例
async def handle_team_member_event(event):
if event.type == "MEMBER_ADDED":
await fga_client.write(writes=[
ClientTupleKey(
user=f"user:{event.user_id}",
relation="member",
object=f"team:{event.team_id}"
)
])
elif event.type == "MEMBER_REMOVED":
await fga_client.write(deletes=[
ClientTupleKeyWithoutCondition(
user=f"user:{event.user_id}",
relation="member",
object=f"team:{event.team_id}"
)
])
5.3 性能考量
OpenFGA 的 Check() 延迟取决于关系图的深度和宽度。根据官方基准和社区反馈:
| 场景 | 典型延迟 | 说明 |
|---|---|---|
| 直接关系 | < 5ms | document:X#editor@user:alice 直接匹配 |
| 一层继承 | 5-15ms | 需要查一次 parent |
| 多层继承 | 15-50ms | 3-4 层嵌套 |
| 复杂模型 | 50-200ms | 多个 union/intersection/exclusion |
优化手段:
- 控制模型深度:继承层级不超过 3-4 层
- 合理使用 ListObjects:批量查询比逐个 Check 高效
- 客户端缓存:对变化不频繁的权限做短时缓存(TTL 30-60s)
- 水平扩展:OpenFGA Server 无状态,可以水平扩展
- 数据库优化:PostgreSQL 配合连接池和索引优化
六、风险分析
6.1 技术风险
| 风险 | 影响 | 缓解措施 |
|---|---|---|
| OpenFGA 服务不可用 | 所有授权决策失败 | 多副本部署 + 客户端缓存 + 降级策略(fail-open 或 fail-close) |
| 数据不一致 | 权限判断错误 | 事件驱动 + 补偿任务 + 定期全量校验 |
| 模型变更导致权限变化 | 意外的权限放大或收缩 | 模型版本管理 + 影子模式验证 + 回滚机制 |
| 性能退化 | 接口延迟增加 | 监控 P99 延迟 + 告警 + 缓存 + 限制模型复杂度 |
| 关系元组膨胀 | 存储和查询压力 | 定期清理孤儿元组 + 监控元组数量 |
6.2 组织风险
- 学习曲线:ReBAC 的思维方式和 RBAC 不同,团队需要时间适应。建议先做内部培训和 Workshop。
- 运维负担:多了一个有状态服务(OpenFGA + PostgreSQL),需要 DBA 和 SRE 支持。
- 供应商锁定:虽然 OpenFGA 是开源的,但如果深度集成后迁移成本很高。
- 社区成熟度:OpenFGA 是 CNCF Sandbox 项目(非 Graduated),社区规模和生态还在成长中。
6.3 降级策略
授权服务是关键路径,必须有降级方案:
async def check_with_fallback(user, relation, obj):
try:
result = await asyncio.wait_for(
fga_client.check(user=user, relation=relation, object=obj),
timeout=0.5 # 500ms 超时
)
return result.allowed
except (TimeoutError, ConnectionError) as e:
logger.error(f"OpenFGA unavailable: {e}")
metrics.increment("authz.fallback")
# 降级策略选择:
# 方案 A: fail-close(安全优先,拒绝所有请求)
# return False
# 方案 B: fail-open(可用性优先,允许所有请求)
# return True
# 方案 C: 回退到本地缓存或旧 RBAC 系统(推荐)
return local_cache.get(f"{user}:{relation}:{obj}", False)
七、开源 vs 自研:取舍之道
这是每个技术团队都会面临的问题。我把市面上的选择梳理一下:
7.1 开源方案对比
| 项目 | 背景 | 模型 | 语言 | 存储 | 成熟度 | 商业支持 |
|---|---|---|---|---|---|---|
| OpenFGA | Auth0/Okta | Zanzibar | Go | PG/MySQL/SQLite | CNCF Sandbox | Okta FGA (SaaS) |
| SpiceDB | Authzed | Zanzibar | Go | PG/CockroachDB/Spanner | 生产就绪 | Authzed (SaaS) |
| Ory Keto | Ory | Zanzibar | Go | PG/MySQL | Beta | Ory Network (SaaS) |
| Casbin | 社区 | RBAC/ABAC/ACL | Go/多语言 | 多种 | 成熟 | 无 |
| OPA | CNCF | 通用策略 | Go | 无(内存) | Graduated | Styra (SaaS) |
OpenFGA vs SpiceDB 是最常被比较的两个:
- OpenFGA:Okta 背书,SDK 丰富(Java/Go/Python/Node/.NET),Playground 好用,社区活跃度高。适合已经在用 Auth0/Okta 生态的团队。
- SpiceDB:API 设计更贴近 Zanzibar 原论文,支持 CockroachDB 和 Spanner(全球分布式),Watch API 更成熟。适合需要全球部署的大规模系统。
7.2 自研的诱惑与代价
我见过不少团队选择自研授权系统,理由通常是:
- "我们的业务模型很特殊,开源方案不够灵活"
- "不想引入外部依赖,增加运维复杂度"
- "我们有能力自己做,而且可以完全掌控"
这些理由都有道理,但自研的代价往往被低估:
自研授权系统的隐性成本:
┌─────────────────────────────────────────────────┐
│ 显性成本(大家都能看到的) │
│ ├── 开发:3-6 个月,2-3 个高级工程师 │
│ └── 测试:权限组合爆炸,测试用例指数增长 │
│ │
│ 隐性成本(容易被忽略的) │
│ ├── 性能优化:图遍历算法、缓存策略、并发控制 │
│ ├── 一致性保证:分布式环境下的数据同步 │
│ ├── 模型演进:业务变化时的 schema migration │
│ ├── 安全审计:权限变更的审计日志和合规报告 │
│ ├── 运维监控:延迟、错误率、元组数量的监控告警 │
│ ├── 文档培训:新人上手成本 │
│ └── 持续维护:Bug 修复、安全补丁、版本升级 │
│ │
│ 机会成本(最容易被忽略的) │
│ └── 这些工程师本可以做什么业务功能? │
└─────────────────────────────────────────────────┘
7.3 我的决策框架
┌──────────────────┐
│ 你的授权需求是? │
└────────┬─────────┘
│
┌────────▼─────────┐
│ 只需要角色级控制? │
└────────┬─────────┘
是 / \ 否
/ \
┌─────────▼┐ ┌────▼──────────┐
│ 用 RBAC │ │ 需要资源级 │
│ (框架自带) │ │ 细粒度控制? │
└──────────┘ └────┬──────────┘
是 / \ 否
/ \
┌─────────▼┐ ┌────▼──────────┐
│ 团队 > 50 │ │ 用 RBAC + ACL │
│ 人?有 SRE │ │ (Casbin/OPA) │
│ 支持? │ └───────────────┘
└─────┬────┘
是 / \ 否
/ \
┌─────────▼┐ ┌────▼──────────┐
│ 用 OpenFGA │ │ 用 OpenFGA │
│ 或 SpiceDB │ │ 但从小处开始 │
│ 全面部署 │ │ 先 PoC 再扩展 │
└───────────┘ └───────────────┘
什么时候该自研?
老实说,只有极少数情况:
- 超大规模:日均 Check 请求 > 10 亿次,需要深度定制存储和缓存层
- 强合规要求:金融/医疗行业,监管要求授权系统必须完全自主可控
- 已有成熟基础设施:团队已经有图数据库、分布式缓存等基础设施,且有专门的平台团队维护
除此之外,用开源方案 + 适度定制 几乎总是更好的选择。
八、实战建议
8.1 授权模型设计原则
- 从业务场景出发,而非从技术出发。先画出"谁能对什么做什么"的关系图,再翻译成 DSL。
- 控制继承深度。超过 4 层的继承会显著影响性能,也会让模型难以理解。
- 显式优于隐式。宁可多写几行 DSL,也不要依赖隐含的权限推导。
- 测试先行。OpenFGA CLI 支持模型测试,把测试用例写在模型旁边:
# model_test.yaml
- name: "folder editor can edit documents in folder"
tuples:
- user: "user:alice"
relation: "editor"
object: "folder:engineering"
- user: "folder:engineering"
relation: "parent"
object: "document:readme"
checks:
- user: "user:alice"
relation: "editor"
object: "document:readme"
assertion: true
- user: "user:bob"
relation: "editor"
object: "document:readme"
assertion: false
8.2 监控指标
上线后必须监控的指标:
授权系统健康度仪表盘:
┌─────────────────────────────────────────────┐
│ Check() P50 延迟 │ Check() P99 延迟 │
│ ████████ 3ms │ ████████████ 45ms │
├──────────────────────┼──────────────────────┤
│ Check() 错误率 │ Write() 吞吐量 │
│ ██ 0.01% │ ████████ 1.2K/s │
├──────────────────────┼──────────────────────┤
│ 关系元组总数 │ 降级触发次数 │
│ ████████ 2.3M │ █ 0 │
└──────────────────────┴──────────────────────┘
8.3 常见陷阱
- 不要把 OpenFGA 当数据库用。它是授权引擎,不是通用存储。不要把业务数据塞进元组。
- 不要忽略元组清理。用户离职、资源删除后,相关元组要及时清理,否则会有"幽灵权限"。
- 不要在热路径上做 ListObjects。ListObjects 比 Check 慢得多,适合用在"展示用户能看到的资源列表"场景,不适合用在每次请求的权限校验中。
- 不要跳过影子模式。直接切换到新系统,出了问题就是线上事故。影子模式是你的安全网。
九、总结
| 维度 | 建议 |
|---|---|
| 模型选择 | RBAC 做粗粒度(API 级),ReBAC 做细粒度(资源级),混合使用 |
| 方案选择 | 优先 OpenFGA/SpiceDB 等开源方案,除非有超大规模或强合规需求才考虑自研 |
| 落地路径 | PoC → 影子模式 → 逐步切换 → 全面迁移,不要一步到位 |
| 数据同步 | 事件驱动 + 幂等写入 + 定期校验 |
| 风险控制 | 降级策略 + 监控告警 + 模型版本管理 + 回滚机制 |
授权系统是那种"做对了没人注意,做错了全公司都知道"的基础设施。选择合适的工具、渐进式落地、持续监控——这三件事做好,就能让这栋楼里的每一把锁都锁得住。
一句话总结:RBAC 是标准间的门卡,OpenFGA 是整栋楼的智能门禁——不是替代,是升级。从小处开始,用影子模式验证,让数据说话。
参考资料
- Google Zanzibar Paper (2019)
- OpenFGA Documentation
- OpenFGA GitHub — Adopted by Grafana, Canonical, Docker, etc.
- SpiceDB GitHub
- NIST RBAC Model (INCITS 359-2004)
- Zanzibar Academy — Interactive Zanzibar learning
- OpenFGA Playground — Online model editor and tester
思维导图

@startmindmap
<style>
mindmapDiagram {
node { BackgroundColor #FAFAFA }
:depth(0) { BackgroundColor #FFD700 }
:depth(1) { BackgroundColor #E3F2FD }
:depth(2) { BackgroundColor #F5F5F5 }
}
</style>
title 从 RBAC 到 OpenFGA
* 授权体系
** RBAC
*** 用户→角色→权限
*** 优势:简单、标准、审计友好
*** 痛点
**** 角色爆炸
**** 无法表达资源关系
**** 动态共享难建模
** Zanzibar / ReBAC
*** 一切权限都是关系
*** Subject ─relation─▶ Object
*** 关系图遍历推导权限
** OpenFGA 架构
*** API Layer (HTTP/gRPC)
*** Query Engine (图遍历)
*** Storage (PG/MySQL/SQLite)
*** 6 个核心 API
**** Check / ListObjects / ListUsers
**** Write / WriteModel / Expand
** 落地路径
*** Phase 1: PoC (2-4周)
*** Phase 2: 影子模式 (4-8周)
*** Phase 3: 逐步切换 (8-16周)
*** Phase 4: 全面迁移
** 数据同步
*** 同步写入(强一致)
*** 事件驱动(最终一致,推荐)
*** 定时全量(弱一致)
** 风险控制
*** 服务不可用 → 降级策略
*** 数据不一致 → 补偿任务
*** 模型变更 → 版本管理
*** 性能退化 → 监控告警
** 开源 vs 自研
*** OpenFGA: Okta 背书, SDK 丰富
*** SpiceDB: 全球分布式
*** 自研:仅超大规模/强合规
*** 决策:用开源 + 适度定制
@endmindmap
本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可。