การให้สิทธิ์และความสมบูรณ์

เมื่อสร้างแอปพลิเคชันที่เปิดเผยต่อสาธารณะ สิ่งสำคัญคือต้องปกป้องข้อมูลที่เก็บไว้ในระบบของคุณ ในเรื่องของ 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 ในแท็บ "Auth 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"}'

ฟังก์ชันระบบคลาวด์สำหรับการผสานรวม Firebase

ปลั๊กอิน Firebase มอบการผสานรวมที่สะดวกกับ Firebase Auth / Google Cloud Identity Platform รวมถึงการรองรับ Firebase App Check ในตัว

การให้สิทธิ์

Wrapper onFlow() ที่ได้จากปลั๊กอิน Firebase ทำงานได้กับSDK ของไคลเอ็นต์ Cloud Functions for Firebase โดยค่าเริ่มต้น เมื่อใช้ SDK ระบบจะรวมส่วนหัวการตรวจสอบสิทธิ์ Firebase ไว้โดยอัตโนมัติตราบใดที่ไคลเอ็นต์ของแอปใช้ Firebase Auth SDK ด้วย คุณสามารถใช้ 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 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 Function ใช้งานได้โดยไม่มีการตรวจสอบการให้สิทธิ์โดยใช้โค้ด (เช่น ฟังก์ชันนั้นเรียกใช้ทั่วโลก แต่ได้รับการปกป้องโดย Cloud IAM แทน) คุณต้องระบุช่อง authPolicy เสมอเมื่อใช้ onFlow() แต่คุณอาจระบุให้ไลบรารีทราบว่ากำลังตรวจสอบการให้สิทธิ์โดยใช้ฟังก์ชัน 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) => {...})

ความสมบูรณ์ของไคลเอ็นต์

การตรวจสอบสิทธิ์เพียงอย่างเดียวจะช่วยปกป้องแอปของคุณได้อย่างมาก แต่สิ่งสำคัญคือต้องดูแลให้มีเพียงแอปไคลเอ็นต์เท่านั้นที่เรียกใช้ฟังก์ชันของคุณ ปลั๊กอิน Firebase สำหรับ genkit รองรับ 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) => {...})

การให้สิทธิ์ HTTP ที่ไม่ใช่ Firebase

เมื่อทำให้โฟลว์ใช้งานได้ในบริบทเซิร์ฟเวอร์นอก 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