授权和完整性

在构建任何面向公众的应用时,保护系统中存储的数据至关重要。对于 LLM,您需要格外小心,以确保模型仅访问应访问的数据,工具调用应正确限定为调用 LLM 的用户,并且只有经过验证的客户端应用才能调用该流程。

Firebase Genkit 提供了用于管理授权政策和上下文的机制。对于在 Cloud Functions for Firebase 上运行的流程,开发者必须提供身份验证政策,否则必须明确声明不提供身份验证政策。对于非函数流程,您也可以管理和设置身份验证,但需要进行更多手动集成。

基本流程授权

所有流程都可以在其配置中定义 authPolicy。身份验证政策是一种函数,用于测试是否满足特定条件(由您定义),并在任何测试失败时抛出异常。如果设置了此字段,系统会在调用流程之前执行该字段:

import { genkit, z } from 'genkit';

const ai = genkit({ ... });

export const selfSummaryFlow = ai.defineFlow(
  {
    name: 'selfSummaryFlow',
    inputSchema: z.object({ uid: z.string() }),
    outputSchema: z.string(),
    authPolicy: (auth, input) => {
      if (!auth) {
        throw new Error('Authorization required.');
      }
      if (input.uid !== auth.uid) {
        throw new Error('You may only summarize your own profile data.');
      }
    },
  },
  async (input) => {
    // Flow logic here...
  }
);

执行此流程时,您必须使用 withLocalAuthContext 提供身份验证对象,否则会收到错误消息:

// Error: Authorization required.
await selfSummaryFlow({ uid: 'abc-def' });

// Error: You may only summarize your own profile data.
await selfSummaryFlow(
  { uid: 'abc-def' },
  {
    withLocalAuthContext: { uid: 'hij-klm' },
  }
);

// Success
await selfSummaryFlow(
  { uid: 'abc-def' },
  {
    withLocalAuthContext: { uid: 'abc-def' },
  }
);

使用 Genkit 开发界面运行时,您可以在“Auth JSON”标签页中输入 JSON 以传递 Auth 对象:{"uid": "abc-def"}

您还可以通过调用 getFlowAuth() 在工作流中随时检索工作流的身份验证上下文,包括在工作流调用的函数中:

import { genkit, z } from 'genkit';

const ai = genkit({ ... });;

async function readDatabase(uid: string) {
  const auth = ai.getAuthContext();
  if (auth?.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 开发者工具测试流程时,您可以在界面中指定此身份验证对象,也可以在命令行中使用 --auth 标志指定此对象:

genkit flow:run selfSummaryFlow '{"uid": "abc-def"}' --auth '{"uid": "abc-def"}'

Cloud Functions for Firebase 集成

Firebase 插件可轻松与 Firebase Auth / Google Cloud Identity Platform 集成,并提供内置的 Firebase App Check 支持。

授权

Firebase 插件提供的 onFlow() 封装容器可与 Cloud Functions for Firebase 客户端 SDK 原生搭配使用。使用该 SDK 时,只要您的应用客户端也使用 Firebase Auth SDK,系统就会自动添加 Firebase Auth 标头。您可以使用 Firebase Auth 保护使用 onFlow() 定义的流程:

import { genkit } from 'genkit';
import { firebaseAuth } from '@genkit-ai/firebase';
import { onFlow } from '@genkit-ai/firebase/functions';

const ai = genkit({ ... });;

export const selfSummaryFlow = onFlow(
  ai,
  {
    name: 'selfSummaryFlow',
    inputSchema: z.string(),
    outputSchema: z.string(),
    authPolicy: firebaseAuth((user) => {
      if (!user.email_verified && !user.admin) {
        throw new Error('Email not verified');
      }
    }),
  },
  async (input) => {
        // Flow logic here...
  }
);

使用 Firebase Auth 插件时,user 将作为 DecodedIdToken 返回。如上所述,您可以随时通过 getFlowAuth() 检索此对象。在开发期间运行此流程时,您可以以相同的方式传递用户对象:

genkit flow:run selfSummaryFlow '{"uid": "abc-def"}' --auth '{"admin": true}'

默认情况下,Firebase Auth 插件要求客户端发送身份验证标头,但如果您希望允许未经身份验证的用户通过特殊处理访问已通过身份验证的用户(例如,使用追加销售功能),则可以按如下方式配置政策:

authPolicy: firebaseAuth((user) => {
  if (user && !user.email_verified) {
    throw new Error("Logged in users must have verified emails");
  }
}, {required: false}),

每当您向更广泛的互联网公开 Cloud Functions 函数时,都必须使用某种授权机制来保护您的数据和客户的数据,这一点至关重要。尽管如此,有时您需要部署不进行基于代码的授权检查的 Cloud Functions 函数(例如,您的函数不是可供所有人调用的,而是受 Cloud IAM 保护)。使用 onFlow() 时,authPolicy 字段始终是必需的,但您可以使用 noAuth() 函数向库指明您要放弃授权检查:

import { onFlow, noAuth } from "@genkit-ai/firebase/functions";

export const selfSummaryFlow = onFlow(
  ai,
  {
    name: "selfSummaryFlow",
    inputSchema: z.string(),
    outputSchema: z.string(),
    // WARNING: Only do this if you have some other gatekeeping in place, like
    // Cloud IAM!
    authPolicy: noAuth(),
  },
  async (input) => {
        // Flow logic here...
  }
);

客户端完整性

身份验证本身对保护应用大有帮助。但确保只有您的客户端应用调用您的函数也很重要。Genkit 的 Firebase 插件对 Firebase App Check 提供一流的支持。只需将以下配置选项添加到 onFlow() 即可:

import { onFlow } from "@genkit-ai/firebase/functions";

export const selfSummaryFlow = onFlow(
  ai,
  {
    name: "selfSummaryFlow",
    inputSchema: z.string(),
    outputSchema: z.string(),

    // 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: ...,
  },
  async (input) => {
        // Flow logic here...
  }
);

非 Firebase HTTP 授权

将流程部署到 Cloud Functions for Firebase 之外的服务器上下文时,您需要能够在原生流程旁边设置自己的授权检查。您可以采用以下两种方法:

  1. 使用您喜欢的任何服务器框架,并通过流程调用传递身份验证上下文(如上所述)。

  2. 使用内置的 startFlowsServer(),并在流程配置中提供 Express 中间件:

    import { genkit, z } from 'genkit';
    
    const ai = genkit({ ... });;
    
    export const selfSummaryFlow = ai.defineFlow(
      {
        name: 'selfSummaryFlow',
        inputSchema: z.object({ uid: z.string() }),
        outputSchema: z.string(),
        middleware: [
          (req, res, next) => {
            const token = req.headers['authorization'];
            const user = yourVerificationLibrary(token);
    
            // Pass auth information to the flow
            req.auth = user;
            next();
          }
        ],
        authPolicy: (auth, input) => {
          if (!auth) {
            throw new Error('Authorization required.');
          }
          if (input.uid !== auth.uid) {
            throw new Error('You may only summarize your own profile data.');
          }
        }
      },
      async (input) => {
        // Flow logic here...
      }
    );
    
    ai.startFlowServer({
      flows: [selfSummaryFlow],
    });  // Registers the middleware
    

    如需详细了解如何使用 Express,请参阅 Cloud Run 说明。

请注意,如果您选择 (1),则在直接调用流程时,系统会忽略 middleware 配置选项。