授權與完整性

建構任何公開的應用程式時,保護儲存在系統中的資料極為重要。處理 LLM 時,您必須確保模型只存取應有的資料,工具呼叫的範圍則適當,限定為叫用 LLM 的使用者,而且只有經過驗證的用戶端應用程式叫用資料流。

Firebase Genkit 提供用來管理授權政策和內容的機制。對於在 Cloud Functions for Firebase 上執行的流程,開發人員必須提供驗證政策,或明確確認缺少驗證政策。如果是非函式流程,您也可以管理及設定驗證,但必須進行更多手動整合。

基本流程授權

所有流程都可以在其設定中定義 authPolicy。驗證政策是一種函式,可以測試是否符合特定條件 (由您定義),並在測試失敗時擲回例外狀況。如果設定這個欄位,則會在叫用流程之前執行:

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 提供驗證物件,否則您會收到錯誤訊息:

// 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 Development UI 執行時,只要在「Auth JSON」分頁中輸入 JSON 來傳遞驗證物件:{"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 開發人員工具測試流程時,您可以在 UI 或指令列中加上 --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 驗證 SDK,系統就會自動納入 Firebase 驗證標頭。您可以使用 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 會以 DecodedIdToken 的形式傳回。您隨時可以透過 getFlowAuth() 擷取這個物件,如上所述。在開發期間執行這個流程時,您會以相同的方式傳遞使用者物件:

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

根據預設,Firebase 驗證外掛程式需要用戶端傳送驗證標頭,但如要允許以特殊方式處理已通過驗證的使用者 (例如向上銷售功能),藉此允許未經驗證的存取權,則可以按照以下方式設定政策:

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

每當您向廣大的網際網路公開 Cloud 函式時,請務必使用某種授權機制來保護資料和客戶資料。不過,有時您必須部署無需程式碼式授權檢查的 Cloud 函式 (例如,您的函式不能世界呼叫,而會受到 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 設定選項。