细粒度授权 (FGA)
细粒度授权是 Mastra Enterprise Edition 的一部分。生产部署需要有效的 EE 许可证。有关更多信息,请联系销售团队。
细粒度授权 (FGA) 为 Mastra 应用添加资源级权限检查。RBAC 回答“此角色能否执行此操作?”,而 FGA 回答**“此用户能否对这个特定资源执行此操作?”**
何时使用 FGA何时使用 FGA的直接链接
FGA 专为权限取决于上下文的多租户 B2B 产品设计:
- 用户可能是团队 A 的管理员,但只是团队 B 的成员
- Thread 访问应限制在用户所属的 Organization 内
- Workflow 执行应限定到特定团队或项目
- Tool 访问取决于用户与资源的关系
配置配置的直接链接
在 Mastra 服务器配置中,将 FGA 与身份验证和 RBAC 一同配置:
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 的派生方式:
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:
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() 在身份验证后设置此值。存储资源 handler 会将作用域持久化到记录元数据中,并按该作用域筛选列表、读取、更新、发布和删除操作。
当作用域需要自定义请求逻辑时,请使用对象:
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 上配置路由策略覆盖范围:
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 元数据。这样可使授权策略与路由相邻:
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()。路由映射比字符串前缀检查更易于扩展:
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 transport 将已认证数据作为 extra.authInfo 传递。如果在启用 FGA 的 Mastra 实例上注册了 MCPServer,请配置 mapAuthInfoToUser,以便 Mastra 在检查 tools/list 和 tools/call 之前设置 requestContext.get('user')。当 MCP Tool 检查所需的资源或权限映射与内部 Agent 和 Workflow Tool 检查不同时,请使用服务器级 fga 选项。请参阅 MCPServer 身份验证上下文。
在此版本中,核心 FGA 不会单独检查对 createRun().start()、resume() 或 restart() 的直接 SDK 调用。请从受保护路由发出这些调用,或在应用代码中保护它们。直接调用受保护入口点时,请传递包含已认证用户的 requestContext。
核心 Agent、内部 Workflow、Tool 和内存检查也会将 requestContext 和操作元数据传递给 FGA Provider。路由检查传递 requestContext。Thread 检查会在可用时传递所属的 resourceId。
自定义 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
}
}
有关所有方法、参数和 ActorSignal 类型,请参阅 IFGAProvider 参考。
系统 Actor系统 Actor的直接链接
自主和计划运行的 Agent 在没有终端用户的情况下运行。请使用 Actor 信号标记这些调用,以便 FGA 将其与用户请求区分开:
true或{ actorKind: 'system' }表示匿名系统 Actor。- 对象形式还可以携带
agentId、permissions和scope,以识别并约束执行操作的 Agent。
默认情况下,受信任 Actor 在完成租户作用域检查后会跳过以用户为中心的 require() 检查。要对每个 Agent 实施最小权限,请在 Provider 上实现可选的 requireActor 方法。它接收 Actor 和与 require 相同的 FGACheckParams,并通过抛出 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 信号是受信任输入,因此请在服务器端构造:
- 将
actor视为每次调用的信号。持久 Workflow 会在运行开始时转发它,但恢复运行时不会还原初始 Actor。每次受信任的恢复都应显式传递它,或通过 AgentdefaultOptions解析新的 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 的授权。