التفويض والتكامل

عند إنشاء أي تطبيق موجه للجمهور، من المهم جدًا حماية البيانات المخزّنة في نظامك. في ما يتعلّق بالنماذج اللغوية الكبيرة، يجب توخي الحذر الشديد لضمان أنّ النموذج لا يصل إلا إلى البيانات التي يجب الوصول إليها، وأنّ طلبات أداة الربط تُحدَّد نطاقها بشكلٍ صحيح للمستخدم الذي يستدعي النموذج اللغوي الكبير، وأنّ عملية الاستدعاء تتم فقط من خلال تطبيقات العملاء التي تم التحقّق منها.

يوفّر Firebase Genkit آليات لإدارة سياسات التفويض و السياقات. يمكن أن تستخدم مسارات المعالجة التي تعمل على Firebase دالة استدعاء (أو أداة مساعدة) لسياسة المصادقة. بدلاً من ذلك، توفّر Firebase أيضًا سياق المصادقة في العملية التي يمكنها إجراء عمليات التحقّق الخاصة بها. بالنسبة إلى عمليات المعالجة التي لا تستخدم Functions، يمكن إدارة المصادقة وإعدادها من خلال الوسيط.

منح الإذن ضمن عملية

يمكن أن تتحقّق مسارات المعالجة من التفويض بطريقتَين: إمّا أن يتم فرض التفويض من خلال عملية ربط الطلب (مثل onCallGenkit لخدمة Cloud Functions في Firebase أو express)، أو يمكن أن تُرسِل هذه الأطر سياسات المصادقة إلى مسار المعالجة نفسه، حيث يمكن لمسار المعالجة الوصول إلى معلومات المصادقة المُدارة ضمن مسار المعالجة.

import { genkit, z, UserFacingError } from 'genkit';

const ai = genkit({ ... });

export const selfSummaryFlow = ai.defineFlow( {
  name: 'selfSummaryFlow',
  inputSchema: z.object({ uid: z.string() }),
  outputSchema: z.string(),
}, async (input, { context }) => {
  if (!context.auth) {
    throw new UserFacingErrorError('UNAUTHENTICATED', 'Unauthenticated');
  }
  if (input.uid !== context.auth.uid) {
    throw new UserFacingError('PERMISSION_DENIED', 'You may only summarize your own profile data.');
  }
  // Flow logic here...
});

يُرجى العِلم أنّه يعود إلى عملية ربط الطلب تعبئة الحقل context.auth في هذه الحالة. على سبيل المثال، تملأ أداة onCallGenkit تلقائيًا context.auth (مصادقة Firebase) وcontext.app (فحص التطبيقات من Firebase) و context.instanceIdToken (المراسلة عبر السحابة الإلكترونية من Firebase). عند استدعاء عملية يدويًا، يمكنك إضافة سياق المصادقة الخاص بك يدويًا.

// Error: Authorization required.
await selfSummaryFlow({ uid: 'abc-def' });

// Error: You may only summarize your own profile data.
await selfSummaryFlow.run(
  { uid: 'abc-def' },
  {
    context: { auth: { uid: 'hij-klm' } },
  }
);

// Success
await selfSummaryFlow(
  { uid: 'abc-def' },
  {
    context: { auth: { uid: 'abc-def' } },
  }
);

عند التشغيل باستخدام واجهة مستخدم تطوير Genkit، يمكنك تمرير عنصر Auth من خلال إدخال ملف JSON في علامة التبويب "Auth JSON": {"uid": "abc-def"}.

يمكنك أيضًا استرداد سياق المصادقة للمسار في أي وقت ضمن المسار من خلال استدعاء ai.currentContext()، بما في ذلك الدوال التي يستدعيها المسار:

import { genkit, z } from 'genkit';

const ai = genkit({ ... });;

async function readDatabase(uid: string) {
  const auth = ai.currentContext()?.auth;
  // Note: the shape of context.auth depends on the provider. onCallGenkit puts
  // claims information in auth.token
  if (auth?.token?.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 هذا في واجهة المستخدم أو في سطر الأوامر باستخدام العلامة --context:

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

تفويض استخدام "وظائف السحابة الإلكترونية لبرنامج Firebase"

تتوافق حِزم تطوير البرامج (SDK) لخدمة "وظائف Firebase السحابية" مع Genkit، بما في ذلك الدمج مع Firebase Auth / Google Cloud Identity Platform، بالإضافة إلى التوافق مع ميزة Firebase App Check المضمّنة.

مصادقة المستخدم

يحتوي الغلاف onCallGenkit() الذي تقدّمه مكتبة Firebase Functions على دعم مضمّن لحِزم تطوير البرامج (SDK) للعملاء في "وظائف السحابة الإلكترونية لبرنامج Firebase". عند استخدام حِزم تطوير البرامج (SDK) هذه، يتم تلقائيًا تضمين عنوان Firebase Auth ما دام حزمة تطوير البرامج (SDK) لنظام Firebase Auth متوفّرة أيضًا في برنامج تشغيل تطبيقك. يمكنك استخدام Firebase Auth لحماية مسارات المستخدمين المحدّدة باستخدام onCallGenkit():

import { genkit } from 'genkit';
import { onCallGenkit } from 'firebase-functions/https';

const ai = genkit({ ... });;

const selfSummaryFlow = ai.defineFlow({
  name: 'selfSummaryFlow',
  inputSchema: z.string(),
  outputSchema: z.string(),
}, async (input) => {
  // Flow logic here...
});

export const selfSummary = onCallGenkit({
  authPolicy: (auth) => auth?.token?.['email_verified'] && auth?.token?.['admin'],
}, selfSummaryFlow);

عند استخدام onCallGenkit، يتم عرض context.auth كعنصر يحتوي على uid لمعرّف المستخدم، وtoken الذي يمثّل DecodedIdToken. يمكنك استرداد هذا العنصر في أي وقت باستخدام ai.currentContext() كما هو مذكور سابقًا. عند تنفيذ هذه العملية أثناء التطوير، عليك تمرير ملف تعريف المستخدِم بالطريقة نفسها:

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

عند إتاحة إحدى وظائف Cloud على الإنترنت بشكل عام، من المهم جدًا استخدام نوع من آلية التفويض لحماية بياناتك وبيانات عملائك. ومع ذلك، هناك أوقات تحتاج فيها إلى نشر دالة Cloud بدون عمليات تحقّق من التفويض المستندة إلى الرموز البرمجية (على سبيل المثال، دالتك غير قابلة للاتّصال من جميع أنحاء العالم، بل محمية بدلاً من ذلك من خلال Cloud IAM). تتيح لك خدمة "وظائف السحابة الإلكترونية لبرنامج Firebase" إجراء ذلك باستخدام موقع invoker، الذي يتحكّم في الوصول إلى إدارة الهوية وإمكانية الوصول. تؤدي القيمة الخاصة 'private' إلى ترك الدالة على النحو التالي: إعدادات IAM التلقائية، ما يعني أنّه لا يمكن تنفيذ الدالة إلا للمتصلين الذين لديهم دور "مُشغِّل Cloud Run". يمكنك بدلاً من ذلك تقديم عنوان البريد الإلكتروني لمستخدم أو حساب خدمة يجب منحه الإذن لاستدعاء هذه السلسلة المتعلّقة بالاستدعاء بالضبط.

import { onCallGenkit } from 'firebase-functions/https'

const selfSummaryFlow = ai.defineFlow({
  name: 'selfSummaryFlow',
  inputSchema: z.string(),
  outputSchema: z.string(),
}, async (input) => {
  // Flow logic here...
});

export const selfSummary = onCallGenkit({
  invoker: 'private',
}, selfSummaryFlow);

سلامة العميل

تساهم المصادقة وحدها في حماية تطبيقك، ولكن من المهم أيضًا ضمان أن تطبيقات العملاء فقط هي التي تستدعي وظائفك. يتضمّن المكوّن الإضافي Firebase لـ genkit دعمًا من الدرجة الأولى لميزة فحص التطبيقات من Firebase. يمكنك إجراء ذلك من خلال إضافة خيارات الضبط التالية إلى onCallGenkit():

import { onCallGenkit } from 'firebase-functions/https';

const selfSummaryFlow = ai.defineFlow({
  name: 'selfSummaryFlow',
  inputSchema: z.string(),
  outputSchema: z.string(),
}, async (input) => {
  // Flow logic here...
});

export const selfSummary = onCallGenkit({
  // 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: ...,
}, selfSummaryFlow);

تفويض HTTP غير التابع لخدمة Firebase

عند نشر عمليات المعالجة في سياق خادم خارج Cloud Functions لأجل Firebase، ستحتاج إلى طريقة لإعداد عمليات التحقّق من الأذونات الخاصة بك إلى جانب عمليات المعالجة المضمّنة.

استخدِم ContextProvider لتعبئة قيم السياق، مثل auth، ولتقديم سياسة توضيحية أو استدعاء سياسة. توفّر حزمة SDK لـ GenkitContextProvider مثل apiKey، وقد تعرِضها أيضًا المكوّنات الإضافية. على سبيل المثال، يعرِض المكوّن الإضافي @genkit-ai/firebase/context مقدّم سياق لإثبات صحة بيانات اعتماد Firebase Auth و ملؤها في السياق.

باستخدام رمز برمجي مثل الرمز التالي الذي قد يظهر في مجموعة متنوعة من التطبيقات:

// Express app with a simple API key
import { genkit, z } from 'genkit';

const ai = genkit({ ... });;

export const selfSummaryFlow = ai.defineFlow(
  {
    name: 'selfSummaryFlow',
    inputSchema: z.object({ uid: z.string() }),
    outputSchema: z.string(),
  },
  async (input) => {
    // Flow logic here...
  }
);

يمكنك تأمين تطبيق تعبيري بسيط من "خادم مسار الإحالة الناجحة" عن طريق كتابة ما يلي:

import { apiKey } from "genkit";
import { startFlowServer, withContext } from "@genkit-ai/express";

startFlowServer({
  flows: [
    withContext(selfSummaryFlow, apiKey(process.env.REQUIRED_API_KEY))
  ],
});

أو يمكنك إنشاء تطبيق سريع مخصّص باستخدام الأدوات نفسها:

import { apiKey } from "genkit";
import * as express from "express";
import { expressHandler } from "@genkit-ai/express;

const app = express();
// Capture but don't validate the API key (or its absence)
app.post('/summary', expressHandler(selfSummaryFlow, { contextProvider: apiKey()}))

app.listen(process.env.PORT, () => {
  console.log(`Listening on port ${process.env.PORT}`);
})

تُنشئ ContextProvider إطار عمل الويب بشكلٍ مجرد، لذا تعمل هذه الأدوات في إطارات عمل أخرى مثل Next.js أيضًا. في ما يلي مثال على تطبيق Firebase تم إنشاؤه باستخدام Next.js.

import { appRoute } from "@genkit-ai/express";
import { firebaseContext } from "@genkit-ai/firebase";

export const POST = appRoute(selfSummaryFlow, { contextProvider: firebaseContext })

لمزيد من المعلومات عن استخدام Express، اطّلِع على تعليمات Cloud Run.