Lorsque vous créez une application publique, il est extrêmement important de protéger les données stockées dans votre système. En ce qui concerne les LLM, une diligence supplémentaire est nécessaire pour s'assurer que le modèle n'accède qu'aux données qu'il doit, que les appels d'outils sont correctement définis pour l'utilisateur qui appelle le LLM et que le flux n'est appelé que par des applications client validées.
Firebase Genkit fournit des mécanismes permettant de gérer les stratégies et les contextes d'autorisation. Les flux exécutés sur Firebase peuvent utiliser un rappel (ou un assistant) de règle d'authentification. Firebase fournit également un contexte d'authentification dans le flux, où il peut effectuer ses propres vérifications. Pour les flux autres que Functions, l'authentification peut être gérée et définie via un middleware.
Autoriser dans un flux
Les flux peuvent vérifier l'autorisation de deux manières: soit la liaison de requête (par exemple, onCallGenkit
pour Cloud Functions pour Firebase ou express
) peut appliquer l'autorisation, soit ces frameworks peuvent transmettre des règles d'authentification au flux lui-même, où le flux a accès aux informations d'authentification gérées dans le flux.
import { genkit, z, UserFacingError } from 'genkit';
const ai = genkit({ ... });
export const selfSummaryFlow = ai.defineFlow( {
name: 'selfSummaryFlow',
inputSchema: z.object({ uid: z.string() }),
outputSchema: z.string(),
}, async (input, { context }) => {
if (!context.auth) {
throw new UserFacingErrorError('UNAUTHENTICATED', 'Unauthenticated');
}
if (input.uid !== context.auth.uid) {
throw new UserFacingError('PERMISSION_DENIED', 'You may only summarize your own profile data.');
}
// Flow logic here...
});
Dans ce cas, c'est la liaison de requête qui doit renseigner context.auth
. Par exemple, onCallGenkit
renseigne automatiquement context.auth
(Firebase Authentication), context.app
(Firebase App Check) et context.instanceIdToken
(Firebase Cloud Messaging). Lorsque vous appelez un flux manuellement, vous pouvez ajouter manuellement votre propre contexte d'authentification.
// Error: Authorization required.
await selfSummaryFlow({ uid: 'abc-def' });
// Error: You may only summarize your own profile data.
await selfSummaryFlow.run(
{ uid: 'abc-def' },
{
context: { auth: { uid: 'hij-klm' } },
}
);
// Success
await selfSummaryFlow(
{ uid: 'abc-def' },
{
context: { auth: { uid: 'abc-def' } },
}
);
Lorsque vous exécutez l'UI de développement Genkit, vous pouvez transmettre l'objet Auth en saisissant du code JSON dans l'onglet "Auth JSON" : {"uid": "abc-def"}
.
Vous pouvez également récupérer le contexte d'authentification du flux à tout moment dans le flux en appelant ai.currentContext()
, y compris dans les fonctions appelées par le flux:
import { genkit, z } from 'genkit';
const ai = genkit({ ... });;
async function readDatabase(uid: string) {
const auth = ai.currentContext()?.auth;
// Note: the shape of context.auth depends on the provider. onCallGenkit puts
// claims information in auth.token
if (auth?.token?.admin) {
// Do something special if the user is an admin
} else {
// Otherwise, use the `uid` variable to retrieve the relevant document
}
}
export const selfSummaryFlow = ai.defineFlow(
{
name: 'selfSummaryFlow',
inputSchema: z.object({ uid: z.string() }),
outputSchema: z.string(),
authPolicy: ...
},
async (input) => {
await readDatabase(input.uid);
}
);
Lorsque vous testez des flux avec les outils de développement Genkit, vous pouvez spécifier cet objet d'authentification dans l'UI ou sur la ligne de commande avec l'indicateur --context
:
genkit flow:run selfSummaryFlow '{"uid": "abc-def"}' --context '{"auth": {"email_verified": true}}'
Autoriser l'utilisation de Cloud Functions for Firebase
Les SDK Cloud Functions pour Firebase sont compatibles avec Genkit, y compris l'intégration à Firebase Auth / Google Cloud Identity Platform, ainsi que la compatibilité intégrée avec Firebase App Check.
Authentification des utilisateurs
Le wrapper onCallGenkit()
fourni par la bibliothèque Firebase Functions est compatible avec les SDK clients Cloud Functions pour Firebase.
Lorsque vous utilisez ces SDK, l'en-tête Firebase Auth est automatiquement inclus tant que le client de votre application utilise également le SDK Firebase Auth.
Vous pouvez utiliser Firebase Authentication pour protéger vos flux définis avec onCallGenkit()
:
import { genkit } from 'genkit';
import { onCallGenkit } from 'firebase-functions/https';
const ai = genkit({ ... });;
const selfSummaryFlow = ai.defineFlow({
name: 'selfSummaryFlow',
inputSchema: z.string(),
outputSchema: z.string(),
}, async (input) => {
// Flow logic here...
});
export const selfSummary = onCallGenkit({
authPolicy: (auth) => auth?.token?.['email_verified'] && auth?.token?.['admin'],
}, selfSummaryFlow);
Lorsque vous utilisez onCallGenkit
, context.auth
est renvoyé en tant qu'objet avec un uid
pour l'ID utilisateur et un token
qui est un DecodedIdToken.
Vous pouvez toujours récupérer cet objet à tout moment à l'aide de ai.currentContext()
, comme indiqué précédemment. Lorsque vous exécutez ce flux pendant le développement, vous devez transmettre l'objet utilisateur de la même manière:
genkit flow:run selfSummaryFlow '{"uid": "abc-def"}' --context '{"auth": {"admin": true}}'
Chaque fois que vous exposez une fonction Cloud à Internet, il est essentiel d'utiliser un mécanisme d'autorisation pour protéger vos données et celles de vos clients. Toutefois, il arrive que vous deviez déployer une fonction Cloud sans aucune vérification d'autorisation basée sur le code (par exemple, votre fonction n'est pas accessible à tous, mais est protégée par Cloud IAM).
Cloud Functions pour Firebase vous permet de le faire à l'aide de la propriété invoker
, qui contrôle l'accès IAM. La valeur spéciale 'private'
laisse la fonction comme paramètre IAM par défaut, ce qui signifie que seuls les appelants disposant du rôle Demandeur Cloud Run peuvent exécuter la fonction. Vous pouvez plutôt fournir l'adresse e-mail d'un utilisateur ou d'un compte de service auquel l'autorisation d'appeler cette fonction exacte doit être accordée.
import { onCallGenkit } from 'firebase-functions/https'
const selfSummaryFlow = ai.defineFlow({
name: 'selfSummaryFlow',
inputSchema: z.string(),
outputSchema: z.string(),
}, async (input) => {
// Flow logic here...
});
export const selfSummary = onCallGenkit({
invoker: 'private',
}, selfSummaryFlow);
Intégrité du client
L'authentification seule permet de protéger votre application dans une large mesure. Toutefois, il est également important de vous assurer que seules vos applications clientes appellent vos fonctions. Le plug-in Firebase pour Genkit inclut une prise en charge de premier ordre de Firebase App Check. Pour ce faire, ajoutez les options de configuration suivantes à votre onCallGenkit()
:
import { onCallGenkit } from 'firebase-functions/https';
const selfSummaryFlow = ai.defineFlow({
name: 'selfSummaryFlow',
inputSchema: z.string(),
outputSchema: z.string(),
}, async (input) => {
// Flow logic here...
});
export const selfSummary = onCallGenkit({
// These two fields for app check. The consumeAppCheckToken option is for
// replay protection, and requires additional client configuration. See the
// App Check docs.
enforceAppCheck: true,
consumeAppCheckToken: true,
authPolicy: ...,
}, selfSummaryFlow);
Autorisation HTTP autre que Firebase
Lorsque vous déployez des flux dans un contexte serveur en dehors de Cloud Functions pour Firebase, vous devez pouvoir configurer vos propres vérifications d'autorisation en plus des flux intégrés.
Utilisez un ContextProvider
pour renseigner des valeurs de contexte telles que auth
et pour fournir une règle déclarative ou un rappel de règle. Le SDK Genkit fournit des ContextProvider
tels que apiKey
, et les plug-ins peuvent également les exposer. Par exemple, le plug-in @genkit-ai/firebase/context
expose un fournisseur de contexte pour valider les identifiants Firebase Authentication et les renseigner dans le contexte.
Avec du code comme celui-ci, qui peut apparaître dans diverses applications:
// Express app with a simple API key
import { genkit, z } from 'genkit';
const ai = genkit({ ... });;
export const selfSummaryFlow = ai.defineFlow(
{
name: 'selfSummaryFlow',
inputSchema: z.object({ uid: z.string() }),
outputSchema: z.string(),
},
async (input) => {
// Flow logic here...
}
);
Vous pouvez sécuriser une application Express "serveur de flux" simple en écrivant:
import { apiKey } from "genkit";
import { startFlowServer, withContext } from "@genkit-ai/express";
startFlowServer({
flows: [
withContext(selfSummaryFlow, apiKey(process.env.REQUIRED_API_KEY))
],
});
Vous pouvez également créer une application Express personnalisée à l'aide des mêmes outils:
import { apiKey } from "genkit";
import * as express from "express";
import { expressHandler } from "@genkit-ai/express;
const app = express();
// Capture but don't validate the API key (or its absence)
app.post('/summary', expressHandler(selfSummaryFlow, { contextProvider: apiKey()}))
app.listen(process.env.PORT, () => {
console.log(`Listening on port ${process.env.PORT}`);
})
ContextProvider
s effectue une abstraction du framework Web. Par conséquent, ces outils fonctionnent également dans d'autres frameworks tels que Next.js. Voici un exemple d'application Firebase créée sur Next.js.
import { appRoute } from "@genkit-ai/express";
import { firebaseContext } from "@genkit-ai/firebase";
export const POST = appRoute(selfSummaryFlow, { contextProvider: firebaseContext })
Pour en savoir plus sur l'utilisation d'Express, consultez les instructions de Cloud Run.