> Discover all available pages from the documentation index: https://mastra.zisheng.pro/zh-HK/llms.txt # 細粒度授權 (FGA) > **備註:** 細粒度授權是 Mastra Enterprise Edition 的一部分。生產環境部署需要有效的 EE 授權。[聯絡銷售團隊](https://mastra.ai/contact)了解詳情。 細粒度授權 (FGA) 為你的 Mastra 應用程式加入資源層級權限檢查。RBAC 回答的是「此角色能否執行此操作?」,而 FGA 回答的則是 **「此用戶能否對這項特定資源執行此操作?」** ## 何時使用 FGA FGA 專為權限取決於具體情境的多租戶 B2B 產品而設: - 用戶可能是團隊 A 的 **管理員**,但只是團隊 B 的 **成員** - Thread 存取權應只限於用戶所屬的機構 - Workflow 執行範圍應限定於特定團隊或項目 - Tool 存取權取決於用戶與資源之間的關係 ## 配置 在 Mastra 伺服器配置中,連同身份驗證和 RBAC 一併配置 FGA: ```typescript import { Mastra } from '@mastra/core/mastra'; import { MastraFGAPermissions } from '@mastra/core/auth/ee'; import { MastraAuthWorkos, MastraFGAWorkos } from '@mastra/auth-workos'; const mastra = new Mastra({ server: { auth: new MastraAuthWorkos({ /* ... */ fetchMemberships: true, mapUserToResourceId: user => user.teamId, }), fga: new MastraFGAWorkos({ resourceMapping: { agent: { fgaResourceType: 'team', deriveId: (ctx) => ctx.user.teamId }, workflow: { fgaResourceType: 'team', deriveId: (ctx) => ctx.user.teamId }, thread: { fgaResourceType: 'workspace-thread', deriveId: ({ resourceId }) => resourceId }, }, permissionMapping: { [MastraFGAPermissions.AGENTS_EXECUTE]: 'manage-workflows', [MastraFGAPermissions.WORKFLOWS_EXECUTE]: 'manage-workflows', [MastraFGAPermissions.MEMORY_READ]: 'read', [MastraFGAPermissions.MEMORY_WRITE]: 'update', }, }), storedResources: { scope: true, }, }, }); ``` 使用 `MastraFGAWorkos` 時,請將 `fetchMemberships: true` 設定於 `MastraAuthWorkos`。WorkOS FGA 檢查需要用戶的機構成員資格,才能解析出正確的成員資格 ID 以進行授權。 記憶體授權的資源映射 key 應使用 `thread`。`MastraFGAWorkos` 仍接受舊有別名 `memory`,但新配置應優先使用 `thread`。 配置 `server.fga` 後,Mastra 會對受保護操作強制執行 FGA。如果受保護操作沒有已驗證身份的用戶,Mastra 會拒絕該操作。如果未配置 `server.fga`,Mastra 會略過這些 FGA 檢查並維持原有行為。 ### 資源映射 `resourceMapping` 告訴 Mastra 如何從請求上下文解析 FGA 資源類型和 ID。key 是 Mastra 資源類型,值則定義 FGA 資源類型及 ID 的衍生方式: ```typescript resourceMapping: { // When checking "can user execute agent X?", resolve the FGA resource // as the user's team (type: 'team', id: user.teamId) agent: { fgaResourceType: 'team', deriveId: (ctx) => ctx.user.teamId, }, } ``` `deriveId()` 會接收: - `user`:已驗證身份的用戶 - `resourceId`:可用時,擁有該資源的 Mastra 資源 ID(例如 Thread 的 `resourceId`) - `requestContext`:目前的請求上下文,用於進階租戶解析 - `metadata`:嘗試執行操作時的 Provider 特定 metadata 傳回 `undefined`,讓 `deriveId()` 退回使用原本的 Mastra 資源 ID。 對於 Thread 和記憶體檢查,Mastra 仍會將原始 `threadId` 作為要檢查的資源傳入,但亦會將擁有該 Thread 的 `resourceId` 轉交至 `deriveId()`。這樣,你便可將 Thread 權限映射至 `userId-teamId-orgId` 等複合租戶 ID。 ### 權限映射 `permissionMapping` 將 Mastra 的內部權限字串轉換成 FGA Provider 的權限 slug: ```typescript import { MastraFGAPermissions } from '@mastra/core/auth/ee'; permissionMapping: { [MastraFGAPermissions.AGENTS_EXECUTE]: 'manage-workflows', // Mastra permission -> WorkOS permission slug [MastraFGAPermissions.MEMORY_READ]: 'read', } ``` 如果某項權限沒有對應映射,系統會直接傳入原始字串。 使用 `validatePermissions()`,在啟動時驗證 Mastra 可能產生的完整權限集合。如果 Provider 要求每項 Mastra 權限均須有明確的 Provider 權限 slug,請使用此方法。 ### 已儲存資源的範圍 FGA 會授權資源存取,但不會自動篩選共用儲存空間內的已儲存記錄。在多租戶應用程式中使用內置已儲存資源 API 時,請啟用已儲存資源範圍設定。 ```typescript const mastra = new Mastra({ server: { auth: new MastraAuthWorkos({ /* ... */ mapUserToResourceId: user => user.teamId, }), storedResources: { scope: true, }, }, }); ``` 設定 `scope: true` 後,Mastra 會從請求上下文讀取 `MASTRA_RESOURCE_ID_KEY`。`mapUserToResourceId()` 會在身份驗證後設定此值。已儲存資源處理程式會將範圍保存至記錄 metadata,並按該範圍篩選列出、讀取、更新、發佈和刪除操作。 如果範圍需要自訂請求邏輯,請使用物件: ```typescript storedResources: { scope: { metadataKey: 'teamId', resolve: ({ user }) => user.teamId, requireScope: true, }, }, ``` 如果 `requireScope` 為 `true` 或省略,當無法解析範圍時,具有範圍限制的已儲存資源路由便會失敗。 ### 路由政策涵蓋範圍 Mastra 為內置資源路由提供路由層級 FGA metadata,涵蓋 Agent、Workflow、Tool、MCP Tool、記憶體 Thread、回應、對話及已儲存資源。已儲存資源路由的涵蓋範圍包括 `/stored/agents`、`/stored/mcp-clients`、`/stored/prompt-blocks`、`/stored/scorers`、`/stored/skills` 和 `/stored/workspaces`。在以下情況下,系統會檢查路由:路由具有路由層級 `fga` metadata、Mastra 能為該路由衍生內置 metadata,或 Provider 透過 `resolveRouteFGA()` 提供 metadata。 若要拒絕無法解析 FGA metadata 的受保護路由,請在 FGA Provider 配置路由政策涵蓋範圍: ```typescript const fga = new MastraFGAWorkos({ resourceMapping: { project: { fgaResourceType: 'project' }, }, permissionMapping: { 'projects:read': 'read', }, requireForProtectedRoutes: true, auditProtectedRoutes: 'warn', validatePermissions: async permissions => { // Throw if a Mastra permission is missing from permissionMapping. }, }); ``` 將 `auditProtectedRoutes: 'error'` 設定為在受保護路由缺少內置 FGA metadata 時令啟動失敗。如果啟用 `requireForProtectedRoutes`,Mastra 預設會將此審核記錄為警告。 對於自訂路由,應優先使用路由層級 `fga` metadata。這可將授權政策與路由放在一起: ```typescript import { createRoute } from '@mastra/server/server-adapter'; export const getProjectRoute = createRoute({ method: 'GET', path: '/projects/:projectId', responseType: 'json', requiresAuth: true, fga: { resourceType: 'project', resourceIdParam: 'projectId', permission: 'projects:read', }, handler: async () => { return { project: null }; }, }); ``` 只有在必須集中從路由、參數或請求上下文衍生路由 metadata 時,才使用 `resolveRouteFGA()`。相較於字串前綴檢查,路由映射更易於擴展: ```typescript import type { FGARouteConfig, FGARouteResolver } from '@mastra/core/auth/ee'; const routeFGA = { 'GET /billing/:accountId': { resourceType: 'account', resourceIdParam: 'accountId', permission: 'billing:read', }, } satisfies Record; const resolveRouteFGA: FGARouteResolver = ({ route }) => routeFGA[`${route.method} ${route.path}`]; const fga = new MastraFGAWorkos({ /* ... */ resolveRouteFGA, }); ``` ## 強制執行點 配置 FGA Provider 後,Mastra 會在以下生命週期節點自動檢查授權: | 生命週期節點 | 檢查的權限 | 資源類型 | 資源 ID | | ------------------------------------------- | -------------------------------------------- | -------------------------------------------- | --------------------------------------------------------- | | Agent 執行(`generate`、`stream`) | `agents:execute` | `agent` | `agentId` | | 內置 Workflow HTTP 執行路由及 `Workflow.execute()` | `workflows:execute` | `workflow` | `workflowId` | | 獨立 Tool 執行 | `tools:execute` | `tool` | `toolName` | | Agent Tool 執行 | `tools:execute` | `tool` | `${agentId}:${toolName}` | | MCP Tool 執行 | `tools:execute` | 預設為 `tool`,或伺服器層級的 `fga.resourceMapping` 覆寫值 | 預設為 `JSON.stringify([serverName, toolName])`,或伺服器層級衍生的 ID | | Thread 及記憶體存取 | `memory:read`、`memory:write`、`memory:delete` | `thread` | `threadId` | | 已儲存資源路由 | 路由操作的已儲存資源權限 | 已儲存資源類型 | 路由記錄 ID;集合路由則為已儲存資源範圍 | | HTTP 資源路由 | 按路由配置 | 按路由配置 | 按路由配置 | 對於受 OAuth 保護的 MCP 伺服器,HTTP MCP 傳輸會將已驗證身份的資料以 `extra.authInfo` 傳入。如果在已啟用 FGA 的 Mastra 執行個體上註冊 `MCPServer`,請配置 `mapAuthInfoToUser`,讓 Mastra 能設定 `requestContext.get('user')`,然後才檢查 `tools/list` 和 `tools/call`。當 MCP Tool 檢查需要採用與內部 Agent 和 Workflow Tool 檢查不同的資源或權限映射時,請使用伺服器層級的 `fga` 選項。請參閱 [MCPServer 身份驗證上下文](https://mastra.zisheng.pro/zh-HK/reference/tools/mcp-server)。 在此版本中,直接呼叫 SDK 的 `createRun().start()`、`resume()` 或 `restart()` 不會由核心 FGA 獨立檢查。請從受保護路由呼叫這些方法,或在應用程式程式碼中加以防護。直接調用受保護進入點時,請傳入包含已驗證身份用戶的 `requestContext`。 核心 Agent、內部 Workflow、Tool 及記憶體檢查亦會將 `requestContext` 和操作 metadata 傳送至 FGA Provider。路由檢查會傳入 `requestContext`。如可取得擁有 Thread 的 `resourceId`,Thread 檢查亦會傳入該值。 ## 自訂 FGA Provider 實作 `IFGAProvider` 以使用任何 FGA 後端: ```typescript import { FGADeniedError } from '@mastra/core/auth/ee' import type { FGACheckParams, IFGAProvider, MastraFGAPermissionInput } from '@mastra/core/auth/ee' class MyFGAProvider implements IFGAProvider { async check(user: any, params: FGACheckParams): Promise { // Your authorization logic return true } async require(user: any, params: FGACheckParams): Promise { const allowed = await this.check(user, params) if (!allowed) { throw new FGADeniedError(user, params.resource, params.permission) } } async filterAccessible( user: any, resources: T[], resourceType: string, permission: MastraFGAPermissionInput, ): Promise { // Filter resources the user can access return resources } } ``` > **備註:** 請參閱 [`IFGAProvider` 參考資料](https://mastra.zisheng.pro/zh-HK/reference/auth/fga),了解每個方法、參數及 `ActorSignal` 類型。 ## 系統 actor 自主及排程 Agent 在沒有終端用戶的情況下執行。請為這些呼叫加上 actor signal,讓 FGA 能夠區分這些呼叫與用戶請求: - `true` 或 `{ actorKind: 'system' }` 代表匿名系統 actor。 - 物件形式亦可包含 `agentId`、`permissions` 和 `scope`,用於識別及限制執行操作的 Agent。 預設情況下,受信任 actor 通過租戶範圍檢查後,會略過以用戶為中心的 `require()` 檢查。若要對每個 Agent 強制執行最小權限,請在 Provider 實作可選的 `requireActor` 方法。它會接收 actor 和相同的 `FGACheckParams`(與 `require` 接收的參數相同),並拋出 `FGADeniedError` 以拒絕操作。如果 Provider 沒有實作 `requireActor`,便會保留受信任 actor 的略過機制,因此加入此方法可向後兼容。 ```typescript import { FGADeniedError } from '@mastra/core/auth/ee' import type { ActorSignal, FGACheckParams, IFGAProvider } from '@mastra/core/auth/ee' class MyFGAProvider implements IFGAProvider { // ...check, require, filterAccessible... async requireActor(actor: ActorSignal, params: FGACheckParams): Promise { const agentId = actor === true ? undefined : actor.agentId // Resolve the agent's real grants from a trusted source keyed by agentId. const granted = await this.grantsForAgent(agentId) const required = Array.isArray(params.permission) ? params.permission : [params.permission] if (!required.some(permission => granted.includes(permission))) { throw new FGADeniedError(null, params.resource, params.permission) } } } ``` ### 信任要求 actor signal 是受信任的輸入,因此必須在伺服器端建立: - 將 `actor` 視為每次呼叫的 signal。持久 Workflow 會在執行開始時轉交它,但不會在恢復時還原最初的 actor。每次受信任的恢復操作都要明確傳入,或透過 Agent `defaultOptions` 解析新的 actor。如果目前沒有 actor,系統便會套用用戶授權,並在缺少用戶時以安全方式拒絕操作。 - Mastra 會從內置 Agent HTTP 路由所處理的執行選項中移除 `actor`。請在伺服器端程式碼(例如排程工作或 Workflow)中設定,切勿從客戶端輸入設定。 - 在伺服器端建立租戶範圍。內置 Agent HTTP 路由會忽略客戶端在請求上下文提供的 `organizationId`,而受信任 actor 路徑則要求必須設定 `organizationId`。 - 持久恢復會保留現有的請求上下文復原及合併行為。這不會令已保存的 actor 在之後的 Workflow 區段中成為受信任 actor。 - 租戶範圍檢查會確認受信任的 `organizationId` 存在,但不會驗證 `actor.agentId` 是否屬於該機構。如有需要確認這項關係,請在 `requireActor` 中使用具權威性的 Provider 資料進行驗證。 - 將 `actor.permissions` 視為未經驗證的聲明。請從受信任來源解析具權威性的授權。強制執行最小權限的 Provider 會從受信任來源解析 Agent 的具權威性權限,例如以 `agentId` 為 key 的 manifest 或 FGA 後端,而非信任 inline 值。 - Provider 一旦實作 `requireActor`,該方法產生的錯誤便會停止執行。Mastra 不會退回只按機構進行授權。 ## 相關內容 - [`IFGAProvider` 參考資料](https://mastra.zisheng.pro/zh-HK/reference/auth/fga) - [身份驗證概覽](https://mastra.zisheng.pro/zh-HK/docs/server/auth) - [WorkOS 身份驗證](https://mastra.zisheng.pro/zh-HK/docs/server/auth/workos)