細粒度授權 (FGA)
細粒度授權是 Mastra Enterprise Edition 的一部分。生產環境部署需要有效的 EE 授權。聯絡銷售團隊了解詳情。
細粒度授權 (FGA) 為你的 Mastra 應用程式加入資源層級權限檢查。RBAC 回答的是「此角色能否執行此操作?」,而 FGA 回答的則是 「此用戶能否對這項特定資源執行此操作?」
何時使用 FGA何時使用 FGA 的直接連結
FGA 專為權限取決於具體情境的多租戶 B2B 產品而設:
- 用戶可能是團隊 A 的 管理員,但只是團隊 B 的 成員
- Thread 存取權應只限於用戶所屬的機構
- Workflow 執行範圍應限定於特定團隊或項目
- Tool 存取權取決於用戶與資源之間的關係
配置配置 的直接連結
在 Mastra 伺服器配置中,連同身份驗證和 RBAC 一併配置 FGA:
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 的衍生方式:
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:
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 時,請啟用已儲存資源範圍設定。
const mastra = new Mastra({
server: {
auth: new MastraAuthWorkos({
/* ... */
mapUserToResourceId: user => user.teamId,
}),
storedResources: {
scope: true,
},
},
});
設定 scope: true 後,Mastra 會從請求上下文讀取 MASTRA_RESOURCE_ID_KEY。mapUserToResourceId() 會在身份驗證後設定此值。已儲存資源處理程式會將範圍保存至記錄 metadata,並按該範圍篩選列出、讀取、更新、發佈和刪除操作。
如果範圍需要自訂請求邏輯,請使用物件:
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 配置路由政策涵蓋範圍:
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。這可將授權政策與路由放在一起:
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()。相較於字串前綴檢查,路由映射更易於擴展:
import type { FGARouteConfig, FGARouteResolver } from '@mastra/core/auth/ee';
const routeFGA = {
'GET /billing/:accountId': {
resourceType: 'account',
resourceIdParam: 'accountId',
permission: 'billing:read',
},
} satisfies Record<string, FGARouteConfig>;
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 身份驗證上下文。
在此版本中,直接呼叫 SDK 的 createRun().start()、resume() 或 restart() 不會由核心 FGA 獨立檢查。請從受保護路由呼叫這些方法,或在應用程式程式碼中加以防護。直接調用受保護進入點時,請傳入包含已驗證身份用戶的 requestContext。
核心 Agent、內部 Workflow、Tool 及記憶體檢查亦會將 requestContext 和操作 metadata 傳送至 FGA Provider。路由檢查會傳入 requestContext。如可取得擁有 Thread 的 resourceId,Thread 檢查亦會傳入該值。
自訂 FGA Provider自訂 FGA Provider 的直接連結
實作 IFGAProvider 以使用任何 FGA 後端:
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<boolean> {
// Your authorization logic
return true
}
async require(user: any, params: FGACheckParams): Promise<void> {
const allowed = await this.check(user, params)
if (!allowed) {
throw new FGADeniedError(user, params.resource, params.permission)
}
}
async filterAccessible<T extends { id: string }>(
user: any,
resources: T[],
resourceType: string,
permission: MastraFGAPermissionInput,
): Promise<T[]> {
// Filter resources the user can access
return resources
}
}
請參閱 IFGAProvider 參考資料,了解每個方法、參數及 ActorSignal 類型。
系統 actor系統 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 的略過機制,因此加入此方法可向後兼容。
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<void> {
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。每次受信任的恢復操作都要明確傳入,或透過 AgentdefaultOptions解析新的 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 不會退回只按機構進行授權。