# 第十四章:OpenFGA — 细粒度授权引擎 > "OpenFGA 让你像 Google 一样管理权限 — 基于关系,而非角色。" ```{mermaid} mindmap root((OpenFGA)) 核心概念 Type Relation Tuple API Check ListObjects Expand Write 授权模型 DSL Google Drive GitHub 多租户 部署 Server PostgreSQL SDK ``` ## 14.1 OpenFGA 是什么 OpenFGA(Fine-Grained Authorization)是由 Auth0/Okta 开源的细粒度授权引擎,基于 Google Zanzibar 论文实现。它是 CNCF Sandbox 项目。 ``` OpenFGA 架构: ┌──────────┐ ┌──────────────────┐ ┌──────────┐ │ 应用 │───▶│ OpenFGA Server │───▶│ 数据存储 │ │ │ │ │ │PostgreSQL│ │ Check() │ │ ┌────────────┐ │ │ MySQL │ │ Write() │ │ │ 授权模型 │ │ │ │ │ List() │ │ │ 关系元组 │ │ │ │ │ │ │ │ 图遍历引擎 │ │ │ │ └──────────┘ │ └────────────┘ │ └──────────┘ └──────────────────┘ ``` ## 14.2 核心概念 ### 授权模型(Authorization Model) ``` # OpenFGA DSL 语法 model schema 1.1 type user type organization relations define admin: [user] define member: [user] or admin type document relations define owner: [user] define editor: [user, organization#member] define viewer: [user, organization#member] or editor or owner define can_edit: editor or owner define can_view: viewer define can_delete: owner ``` ### 关系元组(Relationship Tuple) ``` # 格式:object#relation@subject # Alice 是 budget 文档的 owner document:budget#owner@user:alice # Bob 是 budget 文档的 editor document:budget#editor@user:bob # Acme 组织的所有 member 都是 roadmap 文档的 viewer document:roadmap#viewer@organization:acme#member # Carol 是 Acme 组织的 member organization:acme#member@user:carol → 因此 Carol 可以查看 roadmap 文档(通过关系链推导) ``` ### API 操作 | API | 功能 | 示例 | |-----|------|------| | Check | 检查是否有权限 | Carol 能查看 roadmap 吗?→ ✅ | | ListObjects | 列出有权限的对象 | Carol 能查看哪些文档? | | ListUsers | 列出有权限的用户 | 谁能编辑 budget? | | Expand | 展开权限关系树 | budget 的 viewer 包含哪些人? | | Write | 写入关系元组 | 添加/删除权限关系 | | Read | 读取关系元组 | 查询已有的权限关系 | ## 14.3 实战场景:Google Drive 权限模型 ``` model schema 1.1 type user type group relations define member: [user, group#member] type folder relations define owner: [user] define editor: [user, group#member] or owner define viewer: [user, group#member] or editor define parent: [folder] # 继承父文件夹的权限 define can_edit: editor or owner or can_edit from parent define can_view: viewer or can_edit or can_view from parent type document relations define owner: [user] define editor: [user, group#member] or owner define viewer: [user, group#member] or editor define parent: [folder] define can_edit: editor or owner or can_edit from parent define can_view: viewer or can_edit or can_view from parent define can_share: owner define can_delete: owner ``` ``` 关系元组示例: # 文件夹层次 folder:engineering#parent@folder:root folder:backend#parent@folder:engineering # 文档归属 document:api-spec#parent@folder:backend # 权限分配 folder:root#viewer@group:all-employees#member folder:engineering#editor@group:eng-team#member document:api-spec#owner@user:alice # 权限推导: # Bob 是 eng-team 的 member # → Bob 是 engineering 文件夹的 editor # → Bob 是 backend 文件夹的 editor(继承) # → Bob 可以编辑 api-spec 文档(继承) ``` ## 14.4 Python SDK 完整示例 ```python import asyncio from openfga_sdk import ( ClientConfiguration, OpenFgaClient, ClientWriteRequest, ClientTupleKey, ClientCheckRequest, ClientListObjectsRequest, ) from openfga_sdk.client.models import WriteAuthorizationModelRequest async def main(): # 1. 配置客户端 config = ClientConfiguration( api_url="http://localhost:8080", store_id="your-store-id", ) async with OpenFgaClient(config) as client: # 2. 创建授权模型 model = WriteAuthorizationModelRequest( schema_version="1.1", type_definitions=[ {"type": "user"}, { "type": "document", "relations": { "owner": {"this": {}}, "editor": {"this": {}}, "viewer": { "union": { "child": [ {"this": {}}, {"computedUserset": {"relation": "editor"}}, {"computedUserset": {"relation": "owner"}}, ] } }, }, "metadata": { "relations": { "owner": {"directly_related_user_types": [{"type": "user"}]}, "editor": {"directly_related_user_types": [{"type": "user"}]}, "viewer": {"directly_related_user_types": [{"type": "user"}]}, } }, }, ], ) auth_model = await client.write_authorization_model(model) print(f"模型 ID: {auth_model.authorization_model_id}") # 3. 写入关系元组 await client.write(ClientWriteRequest( writes=[ ClientTupleKey( user="user:alice", relation="owner", object="document:budget", ), ClientTupleKey( user="user:bob", relation="editor", object="document:budget", ), ClientTupleKey( user="user:carol", relation="viewer", object="document:budget", ), ] )) print("关系元组写入成功") # 4. 检查权限 result = await client.check(ClientCheckRequest( user="user:bob", relation="viewer", object="document:budget", )) print(f"Bob 能查看 budget? {result.allowed}") # True(editor 隐含 viewer) result = await client.check(ClientCheckRequest( user="user:carol", relation="editor", object="document:budget", )) print(f"Carol 能编辑 budget? {result.allowed}") # False # 5. 列出用户可访问的文档 objects = await client.list_objects(ClientListObjectsRequest( user="user:alice", relation="viewer", type="document", )) print(f"Alice 可查看的文档: {objects.objects}") asyncio.run(main()) ``` ## 14.5 OpenFGA 部署 ```yaml # docker-compose.yml services: postgres: image: postgres:16 environment: POSTGRES_USER: openfga POSTGRES_PASSWORD: openfga_password POSTGRES_DB: openfga volumes: - pgdata:/var/lib/postgresql/data openfga-migrate: image: openfga/openfga:latest command: migrate environment: OPENFGA_DATASTORE_ENGINE: postgres OPENFGA_DATASTORE_URI: postgres://openfga:openfga_password@postgres:5432/openfga?sslmode=disable depends_on: - postgres openfga: image: openfga/openfga:latest command: run environment: OPENFGA_DATASTORE_ENGINE: postgres OPENFGA_DATASTORE_URI: postgres://openfga:openfga_password@postgres:5432/openfga?sslmode=disable ports: - "8080:8080" # HTTP API - "8081:8081" # gRPC API - "3000:3000" # Playground depends_on: openfga-migrate: condition: service_completed_successfully volumes: pgdata: ``` ## 14.6 OpenFGA vs RBAC | 维度 | RBAC | OpenFGA (ReBAC) | |------|------|-----------------| | 授权依据 | 角色 | 关系 | | 粒度 | 角色级 | 对象级 | | "谁能访问X" | 需要遍历所有角色 | 直接查询 | | "X能访问什么" | 需要遍历所有资源 | ListObjects API | | 继承 | 角色层次 | 关系链(更灵活) | | 性能 | O(1) 角色检查 | 图遍历(有缓存) | | 适用场景 | 简单权限 | 协作应用、SaaS | ## 14.7 小结 - OpenFGA 基于 Google Zanzibar,提供**关系驱动的细粒度授权** - 核心是**关系元组**:`object#relation@subject` - 支持**权限继承**(通过关系链推导) - 提供 Check、ListObjects、ListUsers 等丰富的 API - 适合**协作应用**(文档、项目管理)和**多租户 SaaS** - 与 RBAC 相比,OpenFGA 在资源级别的细粒度控制上更有优势