授权和完整性

在构建任何面向公众的应用时,保护存储在您系统中的数据极为重要。对于 LLM,需要采取额外的措施,以确保模型只访问它应该访问的数据,将工具调用的范围适当地限定为调用 LLM 的用户,并且只有经过验证的客户端应用可以调用该流程。

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

基本流授权

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

import { defineFlow, runFlow } from '@genkit-ai/flow';

export const selfSummaryFlow = 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) => { ... });

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

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

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

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

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

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

import { getFlowAuth, defineFlow } from '@genkit-ai/flow';

async function readDatabase(uid: string) {
  if (getFlowAuth().admin) {
    // Do something special if the user is an admin:
    ...
  } else {
    // Otherwise, use the `uid` variable to retrieve the relevant document
    ...
  }
}

export const selfSummaryFlow = 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 {firebaseAuth} from "@genkit-ai/firebase/auth";
import {onFlow} from "@genkit-ai/firebase/functions";

export const selfSummaryFlow = onFlow({
    name: "selfSummaryFlow",
    inputSchema: z.string(),
    outputSchema: z.string(),
    authPolicy: firebaseAuth((user) => {
      if (!user.email_verified && !user.admin) {
        throw new Error("Email not verified");
      }
    }),
  }, (subject) => {...})

使用 Firebase 身份验证插件时,user 将以 DecodingIdToken 的形式返回。如上所述,您随时可以通过 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({
    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(),
  }, (subject) => {...})

客户端完整性

身份验证本身就大大地保护了您的应用。不过,确保只有客户端应用调用您的函数也很重要。适用于 genkit 的 Firebase 插件包含对 Firebase App Check 的一流支持。只需将以下配置选项添加到 onFlow() 即可:

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

export const selfSummaryFlow = onFlow({
    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: ...,
  }, (subject) => {...})

非 Firebase HTTP 授权

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

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

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

    export const selfSummaryFlow = 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);
    
          // This is what will get passed to your authPolicy
          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) => { ... });
    
    startFlowsServer();  // This will register the middleware
    

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

请注意,如果您选择 (1),runFlow() 会忽略 middleware 配置选项。