授權與完整性

建構任何面向大眾的應用程式時,請務必保護系統中儲存的資料。在 LLM 方面,您必須特別小心,確保模型只會存取應有的資料、工具呼叫的範圍正確地指向叫用 LLM 的使用者,且只有經過驗證的用戶端應用程式會叫用流程。

Firebase Genkit 提供管理授權政策和情境的機制。針對在 Cloud Functions for Firebase 上執行的流程,開發人員必須提供驗證政策,否則必須明確承認沒有驗證政策。對於非 Functions 流程,您也可以管理和設定驗證機制,但需要進行更多手動整合。

基本流程授權

所有流程都可以在設定中定義 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 開發人員 UI 執行時,您可以在「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 開發人員工具測試流程時,您可以在 UI 中指定此驗證物件,也可以在指令列中使用 --auth 標記指定:

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

Cloud Functions for Firebase 整合

Firebase 外掛程式可輕鬆整合 Firebase 驗證 / 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 Function 公開給哪些網際網路,都必須使用某種授權機制來保護您的資料和客戶資料。不過,有時您需要部署不含程式碼授權檢查的 Cloud 函式 (例如,您的函式無法供所有人呼叫,而是由 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 設定選項。