استخدام حِزم SDK للمشرف التي تم إنشاؤها

تتيح حِزم تطوير البرامج (SDK) للمشرفين في Firebase Data Connect إمكانية طلب عمليات البحث والتعديل من بيئات موثوقة، مثل "وظائف السحابة" أو الخلفيات المخصّصة أو محطة العمل الخاصة بك. يمكنك إنشاء حزمة SDK مخصّصة للمشرفين بالتوازي مع تصميم المخططات وعمليات البحث والتعديل التي تنشرها في خدمة Data Connect، وذلك بالطريقة نفسها التي تنشئ بها حِزم SDK لتطبيقات العميل. بعد ذلك، يمكنك دمج طرق من حزمة تطوير البرامج (SDK) هذه في منطق الخلفية أو نصوص الإدارة.

كما ذكرنا في موضع آخر، من المهم ملاحظة أنّ طلبات البحث والتعديلات في Data Connect لا يرسلها العملاء في وقت الطلب. بدلاً من ذلك، عند نشر عمليات Data Connect، يتم تخزينها على الخادم مثل "وظائف السحابة". وهذا يعني أنّه كلما نشرت تغييرات على طلبات البحث وعمليات التعديل، عليك أيضًا إعادة إنشاء حِزم SDK للمشرفين وإعادة نشر أي خدمات تعتمد عليها.

قبل البدء

إنشاء حِزم SDK للمشرف

بعد إنشاء مخططات Data Connect وعمليات البحث والتعديل، يمكنك إنشاء حزمة SDK متوافقة خاصة بالمشرف باتّباع الخطوات التالية:

  1. افتح ملف connector.yaml أو أنشئه وأضِف تعريف adminNodeSdk:

    connectorId: default
    generate:
      adminNodeSdk:
        outputDir: ../../dataconnect-generated/admin-generated
        package: "@dataconnect/admin-generated"
        packageJsonDir: ../..
    

    يمكن العثور على ملف connector.yaml عادةً في الدليل نفسه الذي يحتوي على ملفات GraphQL (.gql) التي تتضمّن تعريفات طلب البحث والتعديل. إذا سبق لك إنشاء حِزم SDK للعملاء، تم إنشاء هذا الملف من قبل.

  2. أنشئ حزمة تطوير البرامج (SDK).

    إذا كانت إضافة Data Connect VS Code مثبَّتة، ستحرص دائمًا على إبقاء حِزم SDK التي تم إنشاؤها محدّثة.

    بخلاف ذلك، استخدِم Firebase CLI:

    firebase dataconnect:sdk:generate

    أو لإعادة إنشاء حِزم SDK تلقائيًا عند تعديل ملفات gql:

    firebase dataconnect:sdk:generate --watch

تنفيذ العمليات من حزمة تطوير برامج (SDK) للمشرف

تحتوي حزمة SDK للمشرف التي تم إنشاؤها على واجهات ووظائف تتوافق مع تعريفات gql، ويمكنك استخدامها لتنفيذ عمليات على قاعدة البيانات. على سبيل المثال، لنفترض أنّك أنشأت حزمة SDK لقاعدة بيانات أغاني، بالإضافة إلى طلب بحث، getSongs:

import { initializeApp } from "firebase-admin/app";
import { getSongs } from "@dataconnect/admin-generated";

const adminApp = initializeApp();

const songs = await getSongs(
  { limit: 4 },
  { impersonate: { unauthenticated: true } }
);

لتحديد إعدادات الموصّل، اتّبِع الخطوات التالية:

import { initializeApp } from "firebase-admin/app";
import { getDataConnect } from "firebase-admin/data-connect";
import {
  connectorConfig,
  getSongs,
} from "@dataconnect/admin-generated";

const adminApp = initializeApp();
const adminDc = getDataConnect(connectorConfig);

const songs = await getSongs(
  adminDc,
  { limit: 4 },
  { impersonate: { unauthenticated: true } }
);

انتحال هوية مستخدم لم يتم إثبات هويته

تم تصميم حِزم تطوير البرامج (SDK) الخاصة بالمشرفين ليتم تشغيلها من بيئات موثوقة، وبالتالي يمكنها الوصول إلى قواعد البيانات بدون أي قيود.

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

في المثال أعلاه، يتم تنفيذ طلب البحث getSongs كمستخدم غير مصادق عليه.

انتحال هوية مستخدم

يمكنك أيضًا تنفيذ عمليات نيابةً عن مستخدمين محدّدين من خلال تمرير جزء من رمز مميّز Firebase Authentication أو كله في الخيار impersonate. ويجب على الأقل تحديد معرّف المستخدم في المطالبة الفرعية. (هذه هي القيمة نفسها الخاصة بخادم auth.uid التي يمكنك الرجوع إليها في عمليات Data Connect GraphQL).

عند انتحال هوية مستخدم، لن تنجح العملية إلا إذا اجتازت بيانات المستخدم التي قدّمتها عمليات التحقّق من المصادقة المحدّدة في تعريف GraphQL.

إذا كنت تستدعي حزمة SDK التي تم إنشاؤها من نقطة نهاية يمكن الوصول إليها بشكل علني، من المهم جدًا أن تتطلب نقطة النهاية المصادقة وأن تتحقّق من سلامة رمز المصادقة قبل استخدامه لانتحال هوية مستخدم.

عند استخدام Cloud Functions القابلة للاستدعاء، يتم التحقّق تلقائيًا من رمز المصادقة المميز، ويمكنك استخدامه كما في المثال التالي:

import { HttpsError, onCall } from "firebase-functions/https";

export const callableExample = onCall(async (req) => {
    const authClaims = req.auth?.token;
    if (!authClaims) {
        throw new HttpsError("unauthenticated", "Unauthorized");
    }

    const favoriteSongs = await getMyFavoriteSongs(
        undefined,
        { impersonate: { authClaims } }
    );

    // ...
});

بخلاف ذلك، استخدِم طريقة Admin SDK verifyIdToken للتحقّق من صحة رمز المصادقة وفك تشفيره. على سبيل المثال، لنفترض أنّ نقطة النهاية تم تنفيذها كدالة HTTP عادية وأنّك مرّرت الرمز المميز Firebase Authentication إلى نقطة النهاية باستخدام العنوان authorization، كما هو معتاد:

import { getAuth } from "firebase-admin/auth";
import { onRequest } from "firebase-functions/https";

const auth = getAuth();

export const httpExample = onRequest(async (req, res) => {
    const token = req.header("authorization")?.replace(/^bearer\s+/i, "");
    if (!token) {
        res.sendStatus(401);
        return;
    }
    let authClaims;
    try {
        authClaims = await auth.verifyIdToken(token);
    } catch {
        res.sendStatus(401);
        return;
    }

    const favoriteSongs = await getMyFavoriteSongs(
        undefined,
        { impersonate: { authClaims } }
    );

    // ...
});

يجب تحديد رقم تعريف مستخدم لم يتم الحصول عليه من مصدر يمكن التحقّق منه فقط عند تنفيذ مهام إدارية حقيقية، مثل نقل البيانات، من بيئة آمنة لا يمكن الوصول إليها بشكل علني:

// Never do this if end users can initiate execution of the code!
const favoriteSongs = await getMyFavoriteSongs(
  undefined,
  { impersonate: { authClaims } }
);

التشغيل مع إمكانية الوصول غير المحدود

إذا كنت بصدد تنفيذ عملية تتطلّب أذونات على مستوى المشرف، احذف المَعلمة impersonate من الطلب:

await upsertSong(adminDc, {
  title: songTitle_one,
  instrumentsUsed: [Instrument.VOCAL],
});

يتمتع الإجراء الذي يتم استدعاؤه بهذه الطريقة بإذن وصول كامل إلى قاعدة البيانات. إذا كانت لديك طلبات بحث أو عمليات تعديل مخصّصة لأغراض الإدارة فقط، عليك تحديدها باستخدام التوجيه @auth(level: NO_ACCESS). ويضمن ذلك أنّه يمكن فقط للمتصلين على مستوى المشرف تنفيذ هذه العمليات.