> Discover all available pages from the documentation index: https://mastra.zisheng.pro/llms.txt # Composite Auth `CompositeAuth` 类允许你将多个身份验证 Provider 组合为一个身份验证 handler。它会按顺序尝试各个 Provider,直到其中一个成功。 ## 使用场景 - 同时支持 API 密钥和 OAuth 令牌 - 在不中断现有客户端的情况下迁移身份验证 Provider - 允许多个身份 Provider(例如 Web 使用 Clerk,集成使用 API 密钥) - 逐步推出新的身份验证方法 ## 安装 CompositeAuth 包含在 `@mastra/core` 中,无需安装其他包。 ```typescript import { CompositeAuth } from '@mastra/core/server' ``` ## 用法示例 将 SimpleAuth(用于 API 密钥)与 Clerk(用于用户会话)组合使用: ```typescript import { Mastra } from '@mastra/core' import { CompositeAuth, SimpleAuth } from '@mastra/core/server' import { MastraAuthClerk } from '@mastra/auth-clerk' // API key users type ApiKeyUser = { id: string name: string type: 'api-key' } const apiKeyAuth = new SimpleAuth({ tokens: { 'sk-integration-key-123': { id: 'integration-1', name: 'CI/CD Pipeline', type: 'api-key', }, }, }) // Clerk users (from web app) const clerkAuth = new MastraAuthClerk({ publishableKey: process.env.CLERK_PUBLISHABLE_KEY, secretKey: process.env.CLERK_SECRET_KEY, jwksUri: process.env.CLERK_JWKS_URI, }) export const mastra = new Mastra({ server: { auth: new CompositeAuth([apiKeyAuth, clerkAuth]), }, }) ``` ## 工作原理 收到请求时,CompositeAuth 会: 1. 从 `Authorization` 标头提取令牌 2. 按顺序尝试每个 Provider 的 `authenticateToken()` 方法 3. 返回第一个成功的 Provider 所提供的用户 4. 如果所有 Provider 都失败,则返回 `null`(401 Unauthorized) 进行授权时,它会调用每个 Provider 的 `authorizeUser()` 方法,直到其中一个返回 `true`。 ```typescript // Pseudocode of CompositeAuth behavior async authenticateToken(token, request) { for (const provider of this.providers) { const user = await provider.authenticateToken(token, request); if (user) return user; // First match wins } return null; // All providers failed } ``` ## Provider 顺序 Provider 顺序会影响性能,因此请将最常用的身份验证方法放在首位: ```typescript // If most requests use Clerk, put it first new CompositeAuth([ clerkAuth, // Checked first (most common) apiKeyAuth, // Checked second (less common) ]) // If most requests use API keys, put it first new CompositeAuth([ apiKeyAuth, // Checked first (most common) clerkAuth, // Checked second (less common) ]) ``` ## 多个 OAuth Provider 支持来自不同身份 Provider 的用户: ```typescript import { CompositeAuth } from '@mastra/core/server' import { MastraAuthClerk } from '@mastra/auth-clerk' import { MastraAuthAuth0 } from '@mastra/auth-auth0' const clerkAuth = new MastraAuthClerk({ publishableKey: process.env.CLERK_PUBLISHABLE_KEY, secretKey: process.env.CLERK_SECRET_KEY, jwksUri: process.env.CLERK_JWKS_URI, }) const auth0Auth = new MastraAuthAuth0({ domain: process.env.AUTH0_DOMAIN, audience: process.env.AUTH0_AUDIENCE, }) export const mastra = new Mastra({ server: { auth: new CompositeAuth([clerkAuth, auth0Auth]), }, }) ``` ## 迁移示例 在保持向后兼容的同时从 JWT 迁移到 Clerk: ```typescript import { CompositeAuth } from '@mastra/core/server' import { MastraJwtAuth } from '@mastra/auth' import { MastraAuthClerk } from '@mastra/auth-clerk' // Legacy JWT auth (existing clients) const legacyAuth = new MastraJwtAuth({ secret: process.env.JWT_SECRET, }) // New Clerk auth (new clients) const clerkAuth = new MastraAuthClerk({ publishableKey: process.env.CLERK_PUBLISHABLE_KEY, secretKey: process.env.CLERK_SECRET_KEY, jwksUri: process.env.CLERK_JWKS_URI, }) // Support both during migration export const mastra = new Mastra({ server: { auth: new CompositeAuth([ clerkAuth, // New auth method (preferred) legacyAuth, // Legacy support ]), }, }) ``` ## 与自定义 Provider 配合使用 将内置 Provider 与自定义实现组合使用: ```typescript import { CompositeAuth, SimpleAuth } from '@mastra/core/server' import { MyCustomAuth } from './my-custom-auth' const apiKeyAuth = new SimpleAuth({ tokens: { 'sk-key-123': { id: 'user-1', name: 'API User' }, }, }) const customAuth = new MyCustomAuth({ apiUrl: process.env.CUSTOM_AUTH_URL, }) export const mastra = new Mastra({ server: { auth: new CompositeAuth([apiKeyAuth, customAuth]), }, }) ``` ## 错误处理 CompositeAuth 会静默捕获单个 Provider 的错误并继续尝试下一个,从而避免某个 Provider 失败时阻止身份验证: ```typescript // If clerkAuth throws an error, apiKeyAuth still gets tried new CompositeAuth([clerkAuth, apiKeyAuth]) ``` 要调试身份验证问题,请向自定义 Provider 添加日志记录,或检查各个 Provider 的配置。 ## 限制 - 所有 Provider 共享 `Authorization` 标头中的同一个令牌 - 不同 Provider 的用户类型可能不同(如有需要,请使用可辨识联合类型) - 没有内置方法可识别由哪个 Provider 对请求完成了身份验证 ### 处理不同的用户类型 当 Provider 返回不同的用户类型时,请使用可辨识联合类型: ```typescript type ApiKeyUser = { type: 'api-key' id: string name: string } type ClerkUser = { type: 'clerk' sub: string email: string } type User = ApiKeyUser | ClerkUser // In your application code function handleUser(user: User) { if (user.type === 'api-key') { console.log('API key user:', user.name) } else { console.log('Clerk user:', user.email) } } ```