> Discover all available pages from the documentation index: https://mastra.zisheng.pro/llms.txt # 细粒度授权 (FGA) > **备注:** 细粒度授权是 Mastra Enterprise Edition 的一部分。生产部署需要有效的 EE 许可证。有关更多信息,请[联系销售团队](https://mastra.ai/contact)。 细粒度授权 (FGA) 为 Mastra 应用添加资源级权限检查。RBAC 回答“此角色能否执行此操作?”,而 FGA 回答\*\*“此用户能否对这个特定资源执行此操作?”\*\* ## 何时使用 FGA FGA 专为权限取决于上下文的多租户 B2B 产品设计: - 用户可能是团队 A 的**管理员**,但只是团队 B 的**成员** - Thread 访问应限制在用户所属的 Organization 内 - Workflow 执行应限定到特定团队或项目 - Tool 访问取决于用户与资源的关系 ## 配置 在 Mastra 服务器配置中,将 FGA 与身份验证和 RBAC 一同配置: ```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` 时,请在 `MastraAuthWorkos` 上设置 `fetchMemberships: true`。WorkOS FGA 检查需要用户的 Organization 成员资格来解析用于授权的正确成员资格 ID。 使用 `thread` 作为内存授权的资源映射键。`MastraFGAWorkos` 仍接受旧别名 `memory`,但新配置应优先使用 `thread`。 配置 `server.fga` 后,Mastra 会对受保护操作实施 FGA。如果受保护操作没有已认证用户,Mastra 会拒绝该操作。如果未配置 `server.fga`,则跳过这些 FGA 检查,Mastra 保持之前的行为。 ### 资源映射 `resourceMapping` 告诉 Mastra 如何从请求上下文解析 FGA 资源类型和 ID。键是 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 特定元数据 从 `deriveId()` 返回 `undefined` 可回退到原始 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()` 在身份验证后设置此值。存储资源 handler 会将作用域持久化到记录元数据中,并按该作用域筛选列表、读取、更新、发布和删除操作。 当作用域需要自定义请求逻辑时,请使用对象: ```typescript storedResources: { scope: { metadataKey: 'teamId', resolve: ({ user }) => user.teamId, requireScope: true, }, }, ``` 当 `requireScope` 为 `true` 或省略时,如果无法解析作用域,带作用域的存储资源路由会失败。 ### 路由策略覆盖范围 Mastra 为内置资源路由提供路由级 FGA 元数据,包括 Agent、Workflow、Tool、MCP Tool、内存 Thread、响应、对话和存储资源。存储资源路由覆盖 `/stored/agents`、`/stored/mcp-clients`、`/stored/prompt-blocks`、`/stored/scorers`、`/stored/skills` 和 `/stored/workspaces`。当路由具有路由级 `fga` 元数据、Mastra 可以为该路由派生内置元数据,或 Provider 通过 `resolveRouteFGA()` 提供元数据时,系统会检查该路由。 要拒绝无法解析 FGA 元数据的受保护路由,请在 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 元数据时使启动失败。如果启用 `requireForProtectedRoutes`,Mastra 默认会将此审计记录为警告。 对于自定义路由,请优先使用路由级 `fga` 元数据。这样可使授权策略与路由相邻: ```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 }; }, }); ``` 仅当必须从路由、参数或请求上下文集中派生路由元数据时,才使用 `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 transport 将已认证数据作为 `extra.authInfo` 传递。如果在启用 FGA 的 Mastra 实例上注册了 `MCPServer`,请配置 `mapAuthInfoToUser`,以便 Mastra 在检查 `tools/list` 和 `tools/call` 之前设置 `requestContext.get('user')`。当 MCP Tool 检查所需的资源或权限映射与内部 Agent 和 Workflow Tool 检查不同时,请使用服务器级 `fga` 选项。请参阅 [MCPServer 身份验证上下文](https://mastra.zisheng.pro/reference/tools/mcp-server)。 在此版本中,核心 FGA 不会单独检查对 `createRun().start()`、`resume()` 或 `restart()` 的直接 SDK 调用。请从受保护路由发出这些调用,或在应用代码中保护它们。直接调用受保护入口点时,请传递包含已认证用户的 `requestContext`。 核心 Agent、内部 Workflow、Tool 和内存检查也会将 `requestContext` 和操作元数据传递给 FGA Provider。路由检查传递 `requestContext`。Thread 检查会在可用时传递所属的 `resourceId`。 ## 自定义 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 } } ``` > **备注:** 有关所有方法、参数和 `ActorSignal` 类型,请参阅 [`IFGAProvider` 参考](https://mastra.zisheng.pro/reference/auth/fga)。 ## 系统 Actor 自主和计划运行的 Agent 在没有终端用户的情况下运行。请使用 Actor 信号标记这些调用,以便 FGA 将其与用户请求区分开: - `true` 或 `{ actorKind: 'system' }` 表示匿名系统 Actor。 - 对象形式还可以携带 `agentId`、`permissions` 和 `scope`,以识别并约束执行操作的 Agent。 默认情况下,受信任 Actor 在完成租户作用域检查后会跳过以用户为中心的 `require()` 检查。要对每个 Agent 实施最小权限,请在 Provider 上实现可选的 `requireActor` 方法。它接收 Actor 和与 `require` 相同的 `FGACheckParams`,并通过抛出 `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 信号是受信任输入,因此请在服务器端构造: - 将 `actor` 视为每次调用的信号。持久 Workflow 会在运行开始时转发它,但恢复运行时不会还原初始 Actor。每次受信任的恢复都应显式传递它,或通过 Agent `defaultOptions` 解析新的 Actor。没有当前 Actor 时会应用用户授权,缺少用户则默认拒绝。 - Mastra 会从内置 Agent HTTP 路由处理的执行选项中移除 `actor`。请在服务器端代码中设置它,例如计划任务或 Workflow,切勿使用客户端输入。 - 在服务器端建立租户作用域。内置 Agent HTTP 路由会忽略客户端在请求上下文中提供的 `organizationId`,而受信任 Actor 路径要求设置 `organizationId`。 - 持久恢复会保留现有的请求上下文恢复和合并行为。这不会使持久化的 Actor 在后续 Workflow 段中成为受信任 Actor。 - 租户作用域检查会确认存在受信任的 `organizationId`,但不会验证 `actor.agentId` 是否属于该 Organization。如果这种关系很重要,请在 `requireActor` 中使用权威 Provider 数据进行验证。 - 将 `actor.permissions` 视为未经验证的 claim。请从可信来源解析权威授权。实施最小权限的 Provider 应从可信来源解析 Agent 的权威权限,例如以 `agentId` 为键的清单或 FGA 后端,而不是信任内联值。 - Provider 实现 `requireActor` 后,该方法产生的错误会停止执行。Mastra 不会回退到仅限 Organization 的授权。 ## 相关内容 - [`IFGAProvider` 参考](https://mastra.zisheng.pro/reference/auth/fga) - [身份验证概览](https://mastra.zisheng.pro/docs/server/auth) - [WorkOS 身份验证](https://mastra.zisheng.pro/docs/server/auth/workos)