При создании любого общедоступного приложения чрезвычайно важно защитить данные, хранящиеся в вашей системе. Когда дело доходит до LLM, необходимо проявлять особую осмотрительность, чтобы гарантировать, что модель обращается только к тем данным, которые ей нужны, вызовы инструментов правильно привязаны к пользователю, вызывающему LLM, а поток вызывается только проверенными клиентскими приложениями.
Firebase Genkit предоставляет механизмы для управления политиками и контекстами авторизации. Потоки, работающие в Firebase, могут использовать обратный вызов политики аутентификации (или помощник). В качестве альтернативы Firebase также предоставляет контекст аутентификации в поток, где он может выполнять собственные проверки. Для потоков, не связанных с функциями, аутентификацией можно управлять и устанавливать через промежуточное программное обеспечение.
Авторизация внутри потока
Потоки могут проверять авторизацию двумя способами: либо привязка запроса (например, onCallGenkit
для Cloud Functions для Firebase или express
) может обеспечить авторизацию, либо эти платформы могут передавать политики аутентификации самому потоку, где поток имеет доступ к информации для аутентификации, управляемой внутри потока.
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...
});
В этом случае заполнение context.auth
зависит от привязки запроса. Например, onCallGenkit
автоматически заполняет context.auth
(аутентификация Firebase), context.app
(проверка приложений Firebase) и context.instanceIdToken
(облачный обмен сообщениями Firebase). При вызове потока вручную вы можете вручную добавить собственный контекст аутентификации.
// 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' } },
}
);
При работе с пользовательским интерфейсом разработки Genkit вы можете передать объект Auth, введя JSON на вкладке «Auth JSON»: {"uid": "abc-def"}
.
Вы также можете получить контекст аутентификации для потока в любой момент внутри потока, вызвав ai.currentContext()
, в том числе в функциях, вызываемых потоком:
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);
}
);
При тестировании потоков с помощью инструментов разработки Genkit вы можете указать этот объект аутентификации в пользовательском интерфейсе или в командной строке с помощью флага --context
:
genkit flow:run selfSummaryFlow '{"uid": "abc-def"}' --context '{"auth": {"email_verified": true}}'
Авторизация с использованием облачных функций для Firebase
Облачные функции для SDK Firebase поддерживают Genkit, включая интеграцию с Firebase Auth/Google Cloud Identity Platform, а также встроенную поддержку проверки приложений Firebase.
Аутентификация пользователя
Оболочка onCallGenkit()
предоставляемая библиотекой функций Firebase, имеет встроенную поддержку облачных функций для клиентских SDK Firebase. Когда вы используете эти SDK, заголовок Firebase Auth автоматически включается, если ваш клиент приложения также использует Firebase Auth SDK . Вы можете использовать Firebase Auth для защиты ваших потоков, определенных с помощью 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);
Когда вы используете onCallGenkit
, context.auth
возвращается как объект с uid
для идентификатора пользователя и token
DecodedIdToken . Вы всегда можете получить этот объект в любое время, используя ai.currentContext()
как отмечалось ранее. При запуске этого потока во время разработки вы должны передать объект пользователя таким же образом:
genkit flow:run selfSummaryFlow '{"uid": "abc-def"}' --context '{"auth": {"admin": true}}'
Всякий раз, когда вы предоставляете облачную функцию доступу в Интернет, крайне важно использовать какой-то механизм авторизации для защиты ваших данных и данных ваших клиентов. С учетом вышесказанного, бывают случаи, когда вам необходимо развернуть облачную функцию без проверок авторизации на основе кода (например, ваша функция не может вызываться по всему миру, но вместо этого защищена Cloud IAM ). Облачные функции для Firebase позволяют сделать это с помощью свойства invoker
, которое управляет доступом к IAM. Специальное значение 'private'
оставляет функцию в качестве настройки IAM по умолчанию, что означает, что только вызывающие абоненты с ролью Cloud Run Invoker могут выполнять эту функцию. Вместо этого вы можете указать адрес электронной почты пользователя или учетной записи службы, которой должно быть предоставлено разрешение на вызов именно этой функции.
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);
Целостность клиента
Аутентификация сама по себе имеет большое значение для защиты вашего приложения. Но также важно убедиться, что только ваши клиентские приложения вызывают ваши функции. Плагин Firebase для genkit включает первоклассную поддержку Firebase App Check . Сделайте это, добавив следующие параметры конфигурации в ваш 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);
HTTP-авторизация, отличная от Firebase
При развертывании потоков в контексте сервера за пределами Cloud Functions for Firebase вам понадобится возможность настроить собственные проверки авторизации наряду со встроенными потоками.
Используйте ContextProvider
для заполнения значений контекста, таких как auth
, а также для предоставления декларативной политики или обратного вызова политики. Genkit SDK предоставляет ContextProvider
, например apiKey
, и плагины также могут их предоставлять. Например, плагин @genkit-ai/firebase/context
предоставляет поставщика контекста для проверки учетных данных Firebase Auth и заполнения их в контексте.
С кодом, подобным следующему, который может появляться в различных приложениях:
// 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...
}
);
Вы можете защитить простое экспресс-приложение «сервер потока», написав:
import { apiKey } from "genkit";
import { startFlowServer, withContext } from "@genkit-ai/express";
startFlowServer({
flows: [
withContext(selfSummaryFlow, apiKey(process.env.REQUIRED_API_KEY))
],
});
Или вы можете создать собственное экспресс-приложение, используя те же инструменты:
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
абстрагирует веб-фреймворк, поэтому эти инструменты работают и в других фреймворках, таких как Next.js. Вот пример приложения Firebase, созданного на основе Next.js.
import { appRoute } from "@genkit-ai/express";
import { firebaseContext } from "@genkit-ai/firebase";
export const POST = appRoute(selfSummaryFlow, { contextProvider: firebaseContext })
Дополнительную информацию об использовании Express см. в инструкциях Cloud Run .