从 RBAC 到 OpenFGA:细粒度授权的架构、落地与取舍
Posted on 四 05 3月 2026 in Tech
| 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 的思路很直白:用户 → 角色 → 权限。
flowchart LR
User["User 用户"] --> Role["Role 角色"] --> Permission["Permission 权限"]
Permission --> AR["Action × Resource<br/>(操作 × 资源)"]
一个典型的 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)。
flowchart LR
subgraph RBAC["传统 RBAC"]
direction LR
U[User] --> R[Role] --> P[Permission] --> Res[Resource]
end
subgraph ReBAC["Zanzibar / ReBAC"]
direction LR
S["Subject (谁)"] -->|"relation (什么关系)"| O["Object (什么东西)"]
end
一条关系元组(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 会沿着关系图遍历:
flowchart LR
Alice["user:alice"] -->|editor| Folder["folder:engineering"]
Folder -->|"parent of"| Doc["document:readme"]
Doc -.->|"沿关系推导"| Result["结论: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 整体架构
flowchart TB
subgraph App["应用层"]
SA[Service A]
SB[Service B]
SC[Service C]
SDK["OpenFGA SDK (gRPC/HTTP)"]
SA --> SDK
SB --> SDK
SC --> SDK
end
subgraph Server["OpenFGA Server"]
API["API Layer<br/>(HTTP/gRPC)"]
QE["Query Engine<br/>(图遍历)"]
CT["Change Tracker<br/>(变更日志)"]
Storage["Storage Adapter<br/>PostgreSQL / MySQL / SQLite(beta) / In-Memory"]
API --> Storage
QE --> Storage
CT --> Storage
end
SDK --> API
SDK --> QE
SDK --> CT
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,设计极其克制(另有 CreateStore、ReadChanges 等管理接口):
mindmap
root((OpenFGA API))
写入类
Write 写入/删除关系元组
WriteModel 更新授权模型
查询类
Check 检查某用户是否有某权限
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 吗?",引擎会沿 editor: [user] or owner or editor from parent 分支搜索:
flowchart TB
Q["Alice 能编辑 document:readme 吗?"] --> D1{"直接关系?<br/>document:readme#editor@user:alice"}
Q --> O1{"owner 关系?<br/>Alice 是 readme 的 owner?"}
Q --> P1{"继承关系?<br/>parent folder 的 editor 含 Alice?"}
P1 --> F["找到 folder:engineering"]
F --> D2{"直接关系?"}
F --> O2{"owner 关系?"}
F --> A2{"org admin 关系?<br/>→ 递归继续遍历"}
D1 & O1 & D2 & O2 & A2 -.->|"任一分支 true"| R["最终结果 true ✅"]
(任一分支返回 true 即短路返回,最终结果为 true。)
这个遍历有几个关键优化:
- 并发遍历:多个分支并行检查,任一成功即短路返回
- 缓存:热点元组和中间结果缓存
- 深度限制:防止无限递归(默认最大深度 25)
- 超时控制:单次 Check 有超时限制
四、RBAC vs ReBAC:不是替代,是演进
很多人问:用了 OpenFGA 是不是就不需要 RBAC 了?不是。
flowchart LR
Left["简单 / 粗粒度"] --- ACL["ACL<br/>(列表)"] --> RBAC["RBAC<br/>(角色)"] --> ABAC["ABAC<br/>(属性)"] --> ReBAC["ReBAC<br/>(关系)"] --- Right["灵活 / 细粒度"]
style Left fill:#fff,stroke-dasharray:5 5
style Right fill:#fff,stroke-dasharray:5 5
一条轴线看懂:从左到右,由简单、粗粒度走向灵活、细粒度。
| 维度 | 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 渐进式迁移策略
不要试图一步到位。我建议分四个阶段:
flowchart LR
P1["Phase 1 · 评估与 PoC (2-4 周)<br/>建模 / 原型验证 / 性能测试"]
P2["Phase 2 · 影子模式 (4-8 周)<br/>双写双读 / 对比结果 / 不影响线上"]
P3["Phase 3 · 逐步切换 (8-16 周)<br/>新功能用 FGA / 旧功能保持 / 逐步切换"]
P4["Phase 4 · 全面迁移 (持续)<br/>旧功能迁移 / 下线旧系统"]
P1 --> P2 --> P3 --> P4
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 的关系元组需要和业务数据保持一致。这是落地中 最容易出问题 的地方。
flowchart LR
E1["用户加入团队"] --> W1["Write(team:X#member@user:alice)"]
E2["用户离开团队"] --> D2["Delete(team:X#member@user:alice)"]
E3["文档移动到新文件夹"] --> M3["Delete(doc:Y#parent@folder:old)<br/>Write(doc:Y#parent@folder:new)"]
E4["文档被删除"] --> D4["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 自研的诱惑与代价
我见过不少团队选择自研授权系统,理由通常是:
- "我们的业务模型很特殊,开源方案不够灵活"
- "不想引入外部依赖,增加运维复杂度"
- "我们有能力自己做,而且可以完全掌控"
这些理由都有道理,但自研的代价往往被低估:
mindmap
root((自研授权系统的成本))
显性成本(大家都能看到)
"开发:3-6 个月,2-3 个高级工程师"
"测试:权限组合爆炸,用例指数增长"
隐性成本(容易被忽略)
"性能优化:图遍历 / 缓存 / 并发控制"
"一致性保证:分布式数据同步"
"模型演进:schema migration"
"安全审计:变更日志 / 合规报告"
"运维监控:延迟 / 错误率 / 元组数量"
"文档培训:新人上手成本"
"持续维护:Bug / 安全补丁 / 升级"
机会成本(最容易被忽略)
"这些工程师本可以做什么业务功能?"
7.3 我的决策框架
flowchart TB
Q{"只需要角色级控制?"}
Q -->|是| RBAC["用 RBAC<br/>(框架自带)"]
Q -->|否| Q2{"需要资源级<br/>细粒度控制?"}
Q2 -->|否| ACL["用 RBAC + ACL<br/>(Casbin / OPA)"]
Q2 -->|是| Q3{"团队 > 50 人?<br/>有 SRE 支持?"}
Q3 -->|是| Full["用 OpenFGA 或 SpiceDB<br/>全面部署"]
Q3 -->|否| Small["用 OpenFGA<br/>但从小处开始<br/>先 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 延迟 | 3ms | Check() P99 延迟 | 45ms |
| Check() 错误率 | 0.01% | Write() 吞吐量 | 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 国际许可协议进行许可。