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

เมื่อสร้างแอปพลิเคชันที่แสดงต่อสาธารณะ คุณต้องปกป้องข้อมูลที่จัดเก็บไว้ในระบบของคุณ ในส่วนของ LLM นั้น คุณต้องใช้ความระมัดระวังเป็นพิเศษเพื่อให้แน่ใจว่าโมเดลจะเข้าถึงเฉพาะข้อมูลที่ควรจะเข้าถึง การเรียกใช้เครื่องมือมีขอบเขตที่ถูกต้องสำหรับผู้ใช้ที่เรียกใช้ LLM และมีการเรียกใช้ขั้นตอนโดยแอปพลิเคชันไคลเอ็นต์ที่ยืนยันแล้วเท่านั้น

Firebase Genkit มีกลไกในการจัดการนโยบายการให้สิทธิ์และบริบท สําหรับขั้นตอนที่ทํางานใน Cloud Functions for Firebase นักพัฒนาแอปต้องระบุนโยบายการตรวจสอบสิทธิ์ หรือยอมรับอย่างชัดแจ้งว่าไม่มีนโยบายดังกล่าว สำหรับโฟลว์ที่ไม่ใช่ฟังก์ชัน คุณจะจัดการและตั้งค่าการตรวจสอบสิทธิ์ได้เช่นกัน แต่ต้องมีการผสานรวมด้วยตนเองเพิ่มเติม

การให้สิทธิ์ตามขั้นตอนพื้นฐาน

ขั้นตอนทั้งหมดสามารถกําหนด 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' },
  }
);

เมื่อใช้งานกับ UI การพัฒนา Genkit คุณสามารถส่งออบเจ็กต์ Auth โดยป้อน JSON ในแท็บ "Auth JSON" {"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 Auth / Google Cloud Identity Platform ที่สะดวก รวมถึงรองรับ Firebase App Check ในตัว

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

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

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

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

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

เมื่อทําให้โฟลว์ใช้งานได้ในบริบทเซิร์ฟเวอร์นอก Cloud Functions สําหรับ 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 เมื่อเรียกใช้ขั้นตอนโดยตรง