Otorisasi dan integritas

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

Firebase Genkit menyediakan mekanisme untuk mengelola kebijakan dan konteks otorisasi. Untuk alur yang berjalan di Cloud Functions for Firebase, developer wajib menyediakan kebijakan autentikasi atau secara eksplisit mengonfirmasi bahwa kebijakan tersebut tidak ada. Untuk alur non-Fungsi, autentikasi juga dapat dikelola dan ditetapkan, tetapi memerlukan sedikit integrasi manual.

Otorisasi alur dasar

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

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

Saat menjalankan alur ini, Anda harus memberikan objek autentikasi menggunakan withLocalAuthContext. Jika tidak, Anda akan menerima error:

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

Saat berjalan dengan 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 { 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);
  }
);

Saat menguji alur dengan alat developer 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 client SDK Cloud Functions for Firebase. Saat menggunakan SDK, header Firebase Auth akan otomatis disertakan selama klien aplikasi Anda juga menggunakan Firebase Auth SDK. Anda dapat menggunakan Firebase Auth untuk melindungi alur yang ditentukan dengan 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...
  }
);

Saat menggunakan plugin Firebase Auth, user akan ditampilkan sebagai DecodedIdToken. Anda dapat mengambil objek ini kapan saja melalui getFlowAuth() seperti yang noted 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 mewajibkan header autentikasi dikirim oleh klien, tetapi jika Anda ingin mengizinkan akses yang tidak diautentikasi dengan penanganan khusus untuk pengguna yang diautentikasi (misalnya, fitur upselling), Anda dapat mengonfigurasi kebijakan seperti ini:

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 Anda dan data pelanggan Anda. Dengan demikian, ada kalanya Anda perlu men-deploy Cloud Function tanpa pemeriksaan otorisasi berbasis kode (misalnya, Fungsi Anda tidak dapat dipanggil oleh semua orang, tetapi dilindungi oleh Cloud IAM). Kolom authPolicy selalu diperlukan saat menggunakan onFlow(), tetapi Anda dapat menunjukkan ke library bahwa Anda tidak melakukan pemeriksaan otorisasi dengan menggunakan fungsi 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...
  }
);

Integritas klien

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

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

Otorisasi HTTP non-Firebase

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

  1. Gunakan framework server apa pun yang Anda sukai, dan teruskan konteks autentikasi melalui panggilan alur seperti yang disebutkan di atas.

  2. Gunakan startFlowsServer() bawaan dan berikan middleware Express dalam konfigurasi alur:

    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
    

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

Perhatikan, jika Anda memilih (1), opsi konfigurasi middleware akan diabaikan saat alur dipanggil secara langsung.