Ao criar qualquer aplicativo voltado ao público, é extremamente importante proteger os dados armazenados no sistema. No caso de LLMs, é necessário ter mais diligência para garantir que o modelo acesse apenas os dados necessários, que as chamadas de ferramentas sejam corretamente delimitadas para o usuário que invoca o LLM e que o fluxo seja invocado apenas por aplicativos de cliente verificados.
O Firebase Genkit oferece mecanismos para gerenciar políticas de autorização e contextos. Os fluxos executados no Firebase podem usar um callback (ou auxiliar) de política de autenticação. Como alternativa, o Firebase também fornece o contexto de autenticação no fluxo em que ele pode fazer as próprias verificações. Para fluxos que não são de funções, a autenticação pode ser gerenciada e definida pelo middleware.
Autorizar em um fluxo
Os fluxos podem verificar a autorização de duas maneiras: a vinculação de solicitação
(por exemplo, onCallGenkit
para o Cloud Functions para Firebase ou express
) pode aplicar
a autorização, ou esses frameworks podem transmitir políticas de autenticação para o próprio fluxo,
em que o fluxo tem acesso às informações de autenticação gerenciadas no
fluxo.
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...
});
Cabe à vinculação de solicitação preencher context.auth
nesse caso. Por
exemplo, o onCallGenkit
preenche automaticamente context.auth
(Firebase Authentication), context.app
(Firebase App Check) e
context.instanceIdToken
(Firebase Cloud Messaging). Ao chamar um fluxo
manualmente, você pode adicionar seu próprio contexto de autenticação manualmente.
// 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' } },
}
);
Ao executar com a interface do Genkit Development, é possível transmitir o objeto de autenticação
digitando JSON na guia "Auth JSON": {"uid": "abc-def"}
.
Também é possível recuperar o contexto de autenticação do fluxo a qualquer momento
chamando ai.currentContext()
, inclusive em funções invocadas pelo fluxo:
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);
}
);
Ao testar fluxos com ferramentas de desenvolvimento do Genkit, é possível especificar esse objeto
de autenticação na interface ou na linha de comando com a flag --context
:
genkit flow:run selfSummaryFlow '{"uid": "abc-def"}' --context '{"auth": {"email_verified": true}}'
Autorizar usando o Cloud Functions para Firebase
Os SDKs do Cloud Functions for Firebase oferecem suporte ao Genkit, incluindo a integração com o Firebase Auth / Google Cloud Identity Platform, além do suporte integrado do Firebase App Check.
Autenticação do usuário
O wrapper onCallGenkit()
fornecido pela biblioteca do Firebase Functions tem
suporte integrado aos SDKs de cliente do Cloud Functions para Firebase.
Quando você usa esses SDKs, o cabeçalho do Firebase Auth é incluído automaticamente,
desde que o cliente do app também esteja usando o
SDK do Firebase Auth.
Você pode usar o Firebase Auth para proteger seus fluxos definidos com 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);
Quando você usa onCallGenkit
, context.auth
é retornado como um objeto com
um uid
para o ID do usuário e um token
que é um
DecodedIdToken.
É possível recuperar esse objeto a qualquer momento usando ai.currentContext()
, como
indicado anteriormente. Ao executar esse fluxo durante o desenvolvimento, você transmite o
objeto do usuário da mesma maneira:
genkit flow:run selfSummaryFlow '{"uid": "abc-def"}' --context '{"auth": {"admin": true}}'
Sempre que você expõe uma função do Cloud para a Internet, é de vital importância
usar algum tipo de mecanismo de autorização para proteger seus dados
e os dados dos seus clientes. No entanto, há momentos em que você precisa implantar um Cloud Function sem verificações de autorização baseadas em código. Por exemplo, sua função não pode ser chamada por qualquer pessoa, mas é protegida pelo Cloud IAM.
O Cloud Functions para Firebase permite fazer isso usando a propriedade invoker
,
que controla o acesso do IAM. O valor especial 'private'
deixa a função como
a configuração padrão do IAM, o que significa que apenas os autores de chamadas com o
papel de Chamador do Cloud Run
podem executar a função. Em vez disso, forneça o endereço de e-mail de um usuário
ou de uma conta de serviço que precisa receber permissão para chamar essa função
exata.
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);
Integridade do cliente
A autenticação por si só protege o app, mas também é
importante garantir que apenas os apps clientes estejam chamando as funções. O
plug-in do Firebase para o Genkit inclui suporte de primeira classe para o
Firebase App Check. Para fazer isso,
adicione as seguintes opções de configuração ao 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);
Autorização HTTP que não é do Firebase
Ao implantar fluxos em um contexto de servidor fora do Cloud Functions para Firebase, é importante ter uma maneira de configurar suas próprias verificações de autorização com os fluxos integrados.
Use um ContextProvider
para preencher valores de contexto, como auth
, e
fornecer uma política declarativa ou um callback de política. O SDK
do Genkit fornece ContextProvider
s, como apiKey
, e os plug-ins também podem
expô-los. Por exemplo, o plug-in @genkit-ai/firebase/context
expõe um provedor de contexto para verificar as credenciais do Firebase Auth e
preencher o contexto.
Com um código como o seguinte, que pode aparecer em vários aplicativos:
// 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...
}
);
Você pode proteger um app expresso "flow server" simples escrevendo:
import { apiKey } from "genkit";
import { startFlowServer, withContext } from "@genkit-ai/express";
startFlowServer({
flows: [
withContext(selfSummaryFlow, apiKey(process.env.REQUIRED_API_KEY))
],
});
Ou você pode criar um aplicativo Express personalizado usando as mesmas ferramentas:
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}`);
})
Os ContextProvider
s abstraem o framework da Web, para que essas
ferramentas funcionem em outros frameworks, como o Next.js. Confira um exemplo de um
app do Firebase criado no Next.js.
import { appRoute } from "@genkit-ai/express";
import { firebaseContext } from "@genkit-ai/firebase";
export const POST = appRoute(selfSummaryFlow, { contextProvider: firebaseContext })
Para mais informações sobre o uso do Express, consulte as instruções do Cloud Run.