مجوز و صداقت

هنگام ساخت هر برنامه عمومی، محافظت از داده های ذخیره شده در سیستم شما بسیار مهم است. وقتی نوبت به LLM ها می رسد، دقت بیشتری لازم است تا اطمینان حاصل شود که مدل فقط به داده هایی که باید دسترسی داشته باشد، فراخوانی ابزار به درستی برای کاربر که LLM را فراخوانی می کند، فراخوانی می شود، و جریان فقط توسط برنامه های کاربردی کلاینت تایید شده فراخوانی می شود.

Firebase Genkit مکانیسم هایی را برای مدیریت سیاست ها و زمینه های مجوز ارائه می دهد. برای جریان‌هایی که روی توابع ابری برای Firebase اجرا می‌شوند، توسعه‌دهندگان ملزم به ارائه خط‌مشی احراز هویت هستند یا به صراحت فقدان آن را تأیید کنند. برای جریان های غیر توابع، auth را می توان مدیریت و تنظیم کرد، اما به یکپارچه سازی دستی کمی بیشتر نیاز دارد.

مجوز جریان اصلی

همه جریان ها می توانند یک 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...
  }
);

هنگام اجرای این جریان، باید یک شی auth با استفاده از 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 Development UI، می توانید با وارد کردن JSON در برگه "Auth JSON"، شی Auth را ارسال کنید: {"uid": "abc-def"} .

همچنین می‌توانید با فراخوانی getFlowAuth() ، از جمله در توابعی که توسط جریان فراخوانی می‌شوند، زمینه auth را برای جریان در هر زمانی در جریان بازیابی کنید:

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، می‌توانید این شی auth را در UI یا در خط فرمان با پرچم --auth مشخص کنید:

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

توابع ابری برای ادغام Firebase

افزونه Firebase ادغام راحت با Firebase Auth / Google Cloud Identity Platform و همچنین پشتیبانی داخلی Firebase App Check را فراهم می کند.

مجوز

بسته بندی onFlow() ارائه شده توسط افزونه Firebase به طور بومی با توابع Cloud برای SDK های مشتری Firebase کار می کند. وقتی از 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 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 نادیده گرفته می‌شود.