Otorisasi dan integritas

Saat mem-build aplikasi yang ditampilkan kepada publik, sangat penting untuk melindungi data yang disimpan di sistem Anda. Dalam hal LLM, ketekunan ekstra diperlukan untuk memastikan bahwa model hanya mengakses data yang seharusnya, panggilan alat dicakup dengan benar kepada pengguna yang memanggil LLM, dan alur hanya dipanggil oleh aplikasi klien terverifikasi.

Firebase Genkit menyediakan mekanisme untuk mengelola konteks dan kebijakan otorisasi. Untuk alur yang berjalan di Cloud Functions for Firebase, developer harus menyediakan kebijakan autentikasi atau mengakui kekurangannya secara eksplisit. Untuk alur non-Fungsi, autentikasi juga dapat dikelola dan ditetapkan, tetapi memerlukan sedikit integrasi manual yang lebih banyak.

Otorisasi alur dasar

Semua flow dapat menentukan authPolicy dalam konfigurasinya. Kebijakan autentikasi adalah fungsi yang menguji apakah kriteria tertentu (yang Anda tetapkan) terpenuhi, dan menampilkan pengecualian jika ada pengujian yang gagal. Jika ditetapkan, kolom ini akan dieksekusi sebelum flow dipanggil:

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) => { ... });

Saat menjalankan alur ini, Anda harus menyediakan objek autentikasi menggunakan withLocalAuthContext atau Anda akan menerima error:

// 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' },
  }
);

Saat menjalankan UI Pengembangan Genkit, Anda dapat meneruskan objek Auth dengan memasukkan JSON di tab "Auth JSON": {"uid": "abc-def"}.

Anda juga dapat mengambil konteks autentikasi untuk alur kapan saja dalam alur dengan memanggil getFlowAuth(), termasuk dalam fungsi yang dipanggil oleh alur:

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);
  });

Saat menguji alur dengan alat dev Genkit, Anda dapat menentukan objek autentikasi ini di UI, atau di command line dengan flag --auth:

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

Integrasi Cloud Functions for Firebase

Plugin Firebase menyediakan integrasi yang mudah dengan Firebase Auth / Google Cloud Identity Platform serta dukungan Firebase App Check bawaan.

Otorisasi

Wrapper onFlow() yang disediakan oleh plugin Firebase berfungsi secara native dengan SDK klien Cloud Functions for Firebase. Ketika menggunakan SDK, header Firebase Auth akan otomatis disertakan selama klien aplikasi Anda juga menggunakan Firebase Auth SDK. Anda dapat menggunakan Firebase Auth untuk melindungi flow Anda yang ditentukan dengan 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) => {...})

Saat menggunakan plugin Firebase Auth, user akan ditampilkan sebagai DecodedIdToken. Anda selalu dapat mengambil objek ini kapan saja melalui getFlowAuth() seperti yang disebutkan di atas. Saat menjalankan alur ini selama pengembangan, Anda akan meneruskan objek pengguna dengan cara yang sama:

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

Secara default, plugin Firebase Auth mengharuskan header autentikasi dikirim oleh klien. Namun, jika Anda ingin mengizinkan akses yang tidak diautentikasi dengan penanganan khusus untuk pengguna yang diautentikasi (misalnya fitur upselling), Anda dapat mengonfigurasi kebijakan seperti berikut:

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

Setiap kali Anda mengekspos Cloud Function ke internet yang lebih luas, Anda harus menggunakan semacam mekanisme otorisasi untuk melindungi data dan data pelanggan Anda. Dengan demikian, ada kalanya Anda perlu men-deploy Cloud Function tanpa pemeriksaan otorisasi berbasis kode (misalnya, Function Anda tidak dapat dipanggil global, tetapi dilindungi oleh Cloud IAM). Kolom authPolicy selalu wajib ada saat menggunakan onFlow(), tetapi Anda dapat menunjukkan ke library bahwa Anda ingin membatalkan pemeriksaan otorisasi menggunakan fungsi 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) => {...})

Integritas klien

Autentikasi itu sendiri sangat bermanfaat untuk melindungi aplikasi Anda. Namun, penting juga untuk memastikan bahwa hanya aplikasi klien yang memanggil fungsi Anda. Plugin Firebase untuk genkit menyertakan dukungan terbaik untuk Firebase App Check. Cukup tambahkan opsi konfigurasi berikut ke onFlow() Anda:

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) => {...})

Otorisasi HTTP non-Firebase

Saat men-deploy alur ke konteks server di luar Cloud Functions for Firebase, Anda harus memiliki cara untuk menyiapkan pemeriksaan otorisasi sendiri bersama alur native. Anda memiliki dua opsi:

  1. Gunakan framework server apa pun yang Anda inginkan, dan teruskan konteks autentikasi melalui runFlow() seperti yang disebutkan di atas.

  2. Gunakan startFlowsServer() bawaan dan sediakan middleware Express dalam konfigurasi flow:

    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
    

    Untuk mengetahui informasi selengkapnya tentang penggunaan Express, lihat petunjuk Cloud Run.

Perhatikan bahwa jika menggunakan (1), opsi konfigurasi middleware akan diabaikan oleh runFlow().