Beim Erstellen einer öffentlich zugänglichen Anwendung ist es äußerst wichtig, die in Ihrem System gespeicherten Daten zu schützen. Bei LLMs ist besondere Sorgfalt erforderlich, um sicherzustellen, dass das Modell nur auf die Daten zugreift, auf die es zugreifen soll, dass Toolaufrufe richtig auf den Nutzer beschränkt sind, der das LLM aufruft, und dass der Ablauf nur von geprüften Clientanwendungen aufgerufen wird.
Firebase Genkit bietet Mechanismen zum Verwalten von Autorisierungsrichtlinien und ‑kontexten. Für Abläufe, die auf Firebase ausgeführt werden, kann ein Callback (oder Helper) für die Autorisierungsrichtlinie verwendet werden. Alternativ stellt Firebase auch einen Authentifizierungskontext für den Ablauf bereit, in dem eigene Prüfungen durchgeführt werden können. Bei anderen Aufrufabfolgen kann die Authentifizierung über Middleware verwaltet und festgelegt werden.
Innerhalb eines Ablaufs autorisieren
Die Autorisierung kann auf zwei Arten geprüft werden: Entweder kann die Anfragebindung (z.B. onCallGenkit
für Cloud Functions for Firebase oder express
) die Autorisierung erzwingen oder diese Frameworks können Authentifizierungsrichtlinien an den Ablauf selbst weitergeben, wobei der Ablauf Zugriff auf die Informationen für die Authentifizierung hat, die im Ablauf verwaltet werden.
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...
});
In diesem Fall ist die Anfragebindung dafür verantwortlich, context.auth
auszufüllen. So werden beispielsweise in onCallGenkit
automatisch context.auth
(Firebase Authentication), context.app
(Firebase App Check) und context.instanceIdToken
(Firebase Cloud Messaging) ausgefüllt. Wenn du einen Ablauf manuell aufrufst, kannst du deinen eigenen Authentifizierungskontext manuell hinzufügen.
// 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' } },
}
);
Wenn du die Genkit-Entwicklungs-UI verwendest, kannst du das Auth-Objekt übergeben, indem du JSON auf dem Tab „Auth-JSON“ eingibst: {"uid": "abc-def"}
.
Sie können den Authentifizierungskontext für den Workflow auch jederzeit innerhalb des Workflows abrufen, indem Sie ai.currentContext()
aufrufen, auch in Funktionen, die vom Workflow aufgerufen werden:
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);
}
);
Wenn Sie Abläufe mit den Genkit-Entwicklertools testen, können Sie dieses Authentifizierungsobjekt in der Benutzeroberfläche oder in der Befehlszeile mit dem Flag --context
angeben:
genkit flow:run selfSummaryFlow '{"uid": "abc-def"}' --context '{"auth": {"email_verified": true}}'
Autorisierung mit Cloud Functions for Firebase
Die Cloud Functions for Firebase-SDKs unterstützen Genkit, einschließlich der Einbindung in Firebase Auth / Google Cloud Identity Platform sowie die integrierte Firebase App Check-Unterstützung.
Nutzerauthentifizierung
Der onCallGenkit()
-Wrapper der Firebase Functions-Bibliothek unterstützt die Cloud Functions for Firebase-Client-SDKs.
Wenn Sie diese SDKs verwenden, wird der Firebase Auth-Header automatisch eingefügt, sofern Ihr App-Client auch das Firebase Auth SDK verwendet.
Mit Firebase Auth können Sie Ihre mit onCallGenkit()
definierten Abläufe schützen:
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);
Wenn du onCallGenkit
verwendest, wird context.auth
als Objekt mit einer uid
für die Nutzer-ID und einer token
zurückgegeben, die ein DecodedIdToken ist.
Sie können dieses Objekt jederzeit mit ai.currentContext()
abrufen, wie bereits erwähnt. Wenn Sie diesen Ablauf während der Entwicklung ausführen, übergeben Sie das Nutzerobjekt auf dieselbe Weise:
genkit flow:run selfSummaryFlow '{"uid": "abc-def"}' --context '{"auth": {"admin": true}}'
Wenn Sie eine Cloud-Funktion für das Internet freigeben, ist es äußerst wichtig, dass Sie einen Autorisierungsmechanismus verwenden, um Ihre Daten und die Daten Ihrer Kunden zu schützen. Es gibt jedoch Fälle, in denen Sie eine Cloud-Funktion ohne codebasierte Autorisierungsüberprüfungen bereitstellen müssen. Beispielsweise ist Ihre Funktion nicht öffentlich aufrufbar, sondern wird durch Cloud IAM geschützt.
In Cloud Functions for Firebase können Sie dies mithilfe der Property invoker
tun, mit der der IAM-Zugriff gesteuert wird. Bei dem speziellen Wert 'private'
bleibt die Funktion bei der Standard-IAM-Einstellung. Das bedeutet, dass nur Aufrufer mit der Rolle Cloud Run Invoker die Funktion ausführen können. Sie können stattdessen die E-Mail-Adresse eines Nutzers oder Dienstkontos angeben, dem die Berechtigung zum Aufrufen dieser Funktion erteilt werden soll.
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);
Clientintegrität
Die Authentifizierung allein trägt bereits wesentlich zum Schutz Ihrer App bei. Es ist aber auch wichtig, dafür zu sorgen, dass nur Ihre Client-Apps Ihre Funktionen aufrufen. Das Firebase-Plug-in für Genkit bietet erstklassigen Support für Firebase App Check. Fügen Sie dazu die folgenden Konfigurationsoptionen zu onCallGenkit()
hinzu:
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);
Nicht Firebase-HTTP-Autorisierung
Wenn Sie Workflows in einem Serverkontext außerhalb von Cloud Functions for Firebase bereitstellen, sollten Sie neben den integrierten Workflows auch eigene Autorisierungsüberprüfungen einrichten können.
Verwenden Sie ContextProvider
, um Kontextwerte wie auth
zu füllen und eine deklarative Richtlinie oder einen Richtlinien-Callback anzugeben. Das Genkit SDK stellt ContextProvider
s wie apiKey
bereit. Diese können auch von Plug-ins freigegeben werden. Das @genkit-ai/firebase/context
-Plug-in stellt beispielsweise einen Kontextanbieter bereit, um Firebase Auth-Anmeldedaten zu überprüfen und in den Kontext einzufügen.
Mit Code wie dem folgenden, der in einer Vielzahl von Anwendungen vorkommen kann:
// 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...
}
);
So sichern Sie eine einfache Express-App vom Typ „flow server“:
import { apiKey } from "genkit";
import { startFlowServer, withContext } from "@genkit-ai/express";
startFlowServer({
flows: [
withContext(selfSummaryFlow, apiKey(process.env.REQUIRED_API_KEY))
],
});
Mit denselben Tools können Sie auch eine benutzerdefinierte Express-Anwendung erstellen:
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
abstrahiert das Web-Framework, sodass diese Tools auch in anderen Frameworks wie Next.js funktionieren. Hier ist ein Beispiel für eine Firebase-App, die mit Next.js erstellt wurde.
import { appRoute } from "@genkit-ai/express";
import { firebaseContext } from "@genkit-ai/firebase";
export const POST = appRoute(selfSummaryFlow, { contextProvider: firebaseContext })
Weitere Informationen zur Verwendung von Express finden Sie in der Anleitung für Cloud Run.