从 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

这个模型表达了:

  1. 组织层级:admin 自动是 member
  2. 文件夹权限:org 的 admin 自动是文件夹的 editor
  3. 文档继承:文档继承父文件夹的权限
  4. 显式拒绝:被 blocked 的用户即使有其他权限也无法访问
  5. 分享控制:只有 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

优化手段:

  1. 控制模型深度:继承层级不超过 3-4 层
  2. 合理使用 ListObjects:批量查询比逐个 Check 高效
  3. 客户端缓存:对变化不频繁的权限做短时缓存(TTL 30-60s)
  4. 水平扩展:OpenFGA Server 无状态,可以水平扩展
  5. 数据库优化: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 再扩展"]

什么时候该自研?

老实说,只有极少数情况:

  1. 超大规模:日均 Check 请求 > 10 亿次,需要深度定制存储和缓存层
  2. 强合规要求:金融/医疗行业,监管要求授权系统必须完全自主可控
  3. 已有成熟基础设施:团队已经有图数据库、分布式缓存等基础设施,且有专门的平台团队维护

除此之外,用开源方案 + 适度定制 几乎总是更好的选择。


八、实战建议

8.1 授权模型设计原则

  1. 从业务场景出发,而非从技术出发。先画出"谁能对什么做什么"的关系图,再翻译成 DSL。
  2. 控制继承深度。超过 4 层的继承会显著影响性能,也会让模型难以理解。
  3. 显式优于隐式。宁可多写几行 DSL,也不要依赖隐含的权限推导。
  4. 测试先行。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 常见陷阱

  1. 不要把 OpenFGA 当数据库用。它是授权引擎,不是通用存储。不要把业务数据塞进元组。
  2. 不要忽略元组清理。用户离职、资源删除后,相关元组要及时清理,否则会有"幽灵权限"。
  3. 不要在热路径上做 ListObjects。ListObjects 比 Check 慢得多,适合用在"展示用户能看到的资源列表"场景,不适合用在每次请求的权限校验中。
  4. 不要跳过影子模式。直接切换到新系统,出了问题就是线上事故。影子模式是你的安全网。

九、总结

维度 建议
模型选择 RBAC 做粗粒度(API 级),ReBAC 做细粒度(资源级),混合使用
方案选择 优先 OpenFGA/SpiceDB 等开源方案,除非有超大规模或强合规需求才考虑自研
落地路径 PoC → 影子模式 → 逐步切换 → 全面迁移,不要一步到位
数据同步 事件驱动 + 幂等写入 + 定期校验
风险控制 降级策略 + 监控告警 + 模型版本管理 + 回滚机制

授权系统是那种"做对了没人注意,做错了全公司都知道"的基础设施。选择合适的工具、渐进式落地、持续监控——这三件事做好,就能让这栋楼里的每一把锁都锁得住。

一句话总结:RBAC 是标准间的门卡,OpenFGA 是整栋楼的智能门禁——不是替代,是升级。从小处开始,用影子模式验证,让数据说话。


参考资料


思维导图

@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 国际许可协议进行许可。