Middleware
Mastra 伺服器可以在叫用 API 路由處理器之前或之後執行自訂 middleware 函數。這適用於身份驗證、記錄日誌、注入請求特定的 context,或加入 CORS header 等情況。
Middleware 會接收 Hono Context(c)和 next 函數。如果它傳回 Response,請求便會短路。呼叫 next() 會繼續處理下一個 middleware 或路由處理器。
import { Mastra } from '@mastra/core'
export const mastra = new Mastra({
server: {
middleware: [
{
handler: async (c, next) => {
// Example: Add authentication check
const authHeader = c.req.header('Authorization')
if (!authHeader) {
return new Response('Unauthorized', { status: 401 })
}
await next()
},
path: '/api/*',
},
// Add a global request logger
async (c, next) => {
console.log(`${c.req.method} ${c.req.url}`)
await next()
},
],
},
})
如要將 middleware 附加至單一路由,請將 middleware 選項傳遞給 registerApiRoute:
registerApiRoute('/my-custom-route', {
method: 'GET',
middleware: [
async (c, next) => {
console.log(`${c.req.method} ${c.req.url}`)
await next()
},
],
handler: async c => {
const mastra = c.get('mastra')
return c.json({ message: 'Hello, world!' })
},
})
常見範例常見範例 的直接連結
使用 RequestContextusing-requestcontext 的直接連結
你可以在 runtime 伺服器 middleware 中從請求擷取資料,以填入 RequestContext。在此範例中,temperature-unit 會根據 Cloudflare CF-IPCountry header 設定,確保回應符合用戶的地區設定。
import { Mastra } from '@mastra/core'
import { RequestContext } from '@mastra/core/request-context'
import { testWeatherAgent } from './agents/test-weather-agent'
export const mastra = new Mastra({
agents: { testWeatherAgent },
server: {
middleware: [
async (context, next) => {
const country = context.req.header('CF-IPCountry')
const requestContext = context.get('requestContext')
requestContext.set('temperature-unit', country === 'US' ? 'fahrenheit' : 'celsius')
await next()
},
],
},
})
身份驗證身份驗證 的直接連結
{
handler: async (c, next) => {
const authHeader = c.req.header('Authorization');
if (!authHeader || !authHeader.startsWith('Bearer ')) {
return new Response('Unauthorized', { status: 401 });
}
// Validate token here
await next();
},
path: '/api/*',
}
授權(用戶隔離)授權(用戶隔離) 的直接連結
身份驗證會核實用戶身份;授權則控制他們可以存取的內容。如果沒有按資源 ID 限定範圍,已通過身份驗證的用戶便可能透過猜測 ID 或操控 resourceId 參數,存取其他用戶的 thread。
要將 memory 和 thread 的範圍限定於已通過身份驗證的用戶,最簡單的方法是使用 auth config 中的 mapUserToResourceId callback:
import { Mastra } from '@mastra/core'
export const mastra = new Mastra({
server: {
auth: {
authenticateToken: async token => {
return verifyToken(token) // { id: 'user-123', orgId: 'org-456', ... }
},
mapUserToResourceId: user => user.id,
},
},
})
身份驗證成功後,系統會使用已通過身份驗證的用戶物件呼叫 mapUserToResourceId。傳回值會在 request context 上設為 MASTRA_RESOURCE_ID_KEY,並適用於所有伺服器 adapter(Hono、Express、Next.js 等)。
資源 ID 不一定要是 user.id。常見模式包括:
// Org-scoped
mapUserToResourceId: user => `${user.orgId}:${user.id}`
// From a JWT claim
mapUserToResourceId: user => user.tenantId
// Composite key
mapUserToResourceId: user => `${user.workspaceId}:${user.projectId}:${user.id}`
設定資源 ID 後,伺服器會自動:
- 篩選 thread 列表,只傳回用戶擁有的 thread
- 驗證 thread 存取權限,如嘗試存取其他用戶的 thread,則傳回 403
- 強制建立 thread 時使用已通過身份驗證的用戶 ID
- 驗證訊息操作(包括刪除),確保訊息屬於用戶擁有的 thread
即使用戶端傳遞 ?resourceId=other-user-id,由 auth 設定的值仍會優先採用。嘗試存取其他用戶擁有的 thread 或訊息時,系統會傳回 403 錯誤。
進階:在 middleware 中設定資源 ID進階:在 middleware 中設定資源 ID 的直接連結
對於較複雜的情況(例如從數據庫查找資源 ID),你可以直接在 middleware 中設定 MASTRA_RESOURCE_ID_KEY:
import { Mastra } from '@mastra/core'
import { MASTRA_RESOURCE_ID_KEY } from '@mastra/core/request-context'
import { getAuthenticatedUser } from '@mastra/server/auth'
export const mastra = new Mastra({
server: {
auth: {
authenticateToken: async token => verifyToken(token),
},
middleware: [
{
path: '/api/*',
handler: async (c, next) => {
const token = c.req.header('Authorization')
if (!token) {
return c.json({ error: 'Unauthorized' }, 401)
}
const user = await getAuthenticatedUser<{ id: string }>({
mastra: c.get('mastra'),
token,
request: c.req.raw,
})
const requestContext = c.get('requestContext')
if (!user) {
return c.json({ error: 'Unauthorized' }, 401)
}
requestContext.set(MASTRA_RESOURCE_ID_KEY, user.id)
return next()
},
},
],
},
})
server.middleware 會在 Mastra 各路由的 auth 檢查之前執行。當 middleware 需要已通過身份驗證的用戶時,請呼叫 getAuthenticatedUser(),透過已設定的 auth provider 解析用戶,而不會變更預設的路由 auth 流程。
使用 MASTRA_THREAD_ID_KEYusing-mastra_thread_id_key 的直接連結
你亦可以設定 MASTRA_THREAD_ID_KEY,覆寫用戶端提供的 thread ID:
import { MASTRA_RESOURCE_ID_KEY, MASTRA_THREAD_ID_KEY } from '@mastra/core/request-context'
// Force operations to use a specific thread
requestContext.set(MASTRA_THREAD_ID_KEY, validatedThreadId)
當你想將操作限制於已透過其他方式驗證的特定 thread 時,這項設定十分有用。
CORS 支援CORS 支援 的直接連結
{
handler: async (c, next) => {
c.header('Access-Control-Allow-Origin', '*');
c.header(
'Access-Control-Allow-Methods',
'GET, POST, PUT, DELETE, OPTIONS',
);
c.header(
'Access-Control-Allow-Headers',
'Content-Type, Authorization',
);
if (c.req.method === 'OPTIONS') {
return new Response(null, { status: 204 });
}
await next();
},
}
請求日誌記錄請求日誌記錄 的直接連結
{
handler: async (c, next) => {
const start = Date.now();
await next();
const duration = Date.now() - start;
console.log(`${c.req.method} ${c.req.url} - ${duration}ms`);
},
}