> Discover all available pages from the documentation index: https://mastra.zisheng.pro/fr/llms.txt # Middleware Les serveurs Mastra peuvent exécuter des fonctions middleware personnalisées avant ou après l'appel d'un gestionnaire de route d'API. Cela permet notamment de gérer l'authentification, la journalisation, l'injection d'un contexte propre à la requête ou l'ajout d'en-têtes CORS. Un middleware reçoit le `Context` (`c`) de [Hono](https://hono.dev) ainsi qu'une fonction `next`. S'il renvoie une `Response`, le traitement de la requête est interrompu. L'appel à `next()` poursuit le traitement avec le middleware ou le gestionnaire de route suivant. ```typescript 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() }, ], }, }) ``` Pour associer un middleware à une seule route, transmettez l'option `middleware` à `registerApiRoute` : ```typescript 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!' }) }, }) ``` ## Exemples courants ### Utiliser `RequestContext` Vous pouvez alimenter `RequestContext` dans un middleware du serveur à l'exécution en extrayant des informations de la requête. Dans cet exemple, `temperature-unit` est défini d'après l'en-tête Cloudflare `CF-IPCountry` afin que les réponses correspondent aux paramètres régionaux de l'utilisateur. ```typescript 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() }, ], }, }) ``` ### Authentication ```typescript { 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/*', } ``` ### Autorisation (isolation des utilisateurs) L'authentification vérifie l'identité de l'utilisateur. L'autorisation détermine les ressources auxquelles il peut accéder. Sans délimitation par identifiant de ressource, un utilisateur authentifié pourrait accéder aux threads d'autres utilisateurs en devinant leurs identifiants ou en manipulant le paramètre `resourceId`. Le moyen le plus simple de limiter la Memory et les threads à l'utilisateur authentifié consiste à utiliser le callback `mapUserToResourceId` dans la configuration d'authentification : ```typescript 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, }, }, }) ``` Après une authentification réussie, `mapUserToResourceId` est appelé avec l'objet de l'utilisateur authentifié. La valeur renvoyée est définie comme `MASTRA_RESOURCE_ID_KEY` dans le contexte de requête. Ce mécanisme fonctionne avec tous les adaptateurs de serveur, notamment Hono, Express et Next.js. L'identifiant de ressource ne doit pas nécessairement être `user.id`. Voici quelques modèles courants : ```typescript // 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}` ``` Lorsqu'un identifiant de ressource est défini, le serveur effectue automatiquement les opérations suivantes : - **Filtrage de la liste des threads** afin de ne renvoyer que ceux qui appartiennent à l'utilisateur - **Validation de l'accès aux threads** avec une réponse 403 en cas d'accès au thread d'un autre utilisateur - **Imposition de l'identifiant de l'utilisateur authentifié** lors de la création des threads - **Validation des opérations sur les messages**, y compris la suppression, afin de garantir que les messages appartiennent à des threads détenus par l'utilisateur Même si un client transmet `?resourceId=other-user-id`, la valeur définie par l'authentification prévaut. Toute tentative d'accès à des threads ou messages appartenant à d'autres utilisateurs renvoie une erreur 403. #### Avancé : définir l'identifiant de ressource dans un middleware Dans les scénarios plus complexes, par exemple lorsque vous devez rechercher l'identifiant de ressource dans une base de données, vous pouvez définir `MASTRA_RESOURCE_ID_KEY` directement dans un middleware : ```typescript 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` s'exécute avant les contrôles d'authentification par route de Mastra. Lorsqu'un middleware a besoin de l'utilisateur authentifié, appelez `getAuthenticatedUser()` afin de l'obtenir depuis le Provider d'authentification configuré sans modifier le flux d'authentification par défaut des routes. #### Utiliser `MASTRA_THREAD_ID_KEY` Vous pouvez également définir `MASTRA_THREAD_ID_KEY` pour remplacer l'identifiant de thread fourni par le client : ```typescript 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) ``` Cette approche est utile pour limiter les opérations à un thread précis que vous avez validé par un autre moyen. ### Prise en charge de CORS ```typescript { 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(); }, } ``` ### Journalisation des requêtes ```typescript { 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`); }, } ``` # Voir aussi - [Contexte de requête](https://mastra.zisheng.pro/fr/docs/server/request-context) - [Clés réservées](https://mastra.zisheng.pro/fr/docs/server/request-context)