授权和完整性

在构建任何面向公众的应用时,保护存储在您系统中的数据极为重要。对于 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 配置选项。