استخدام SDK للمشرف مع Data Connect

Firebase Admin SDK هي مجموعة من مكتبات الخادم التي تتيح لك التفاعل مع Firebase من بيئات ذات امتيازات خاصة لتنفيذ إجراءات مثل تنفيذ طلبات البحث والتعديلات على خدمة Firebase Data Connect لإدارة البيانات المجمّعة وعمليات أخرى ذات امتيازات مرتفعة وبيانات اعتماد منتحلة.

توفّر لك Admin SDK واجهة برمجة تطبيقات لاستدعاء العمليات في وضعَي القراءة والكتابة والقراءة فقط. باستخدام عمليات القراءة فقط، يمكنك تنفيذ وظائف إدارية لا يمكنها تعديل البيانات في قواعد البيانات، ما يمنحك راحة البال.

إعداد حزمة SDK للمشرف

لبدء استخدام Firebase Data Connect على خادمك، عليك أولاً تثبيت Admin SDK وإعداده لـ Node.js.

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

لبدء استخدام حزمة SDK، استورِد إضافات Data Connect وحدِّد رقم تعريف خدمة مشروعك وموقعه الجغرافي.


import { initializeApp } from 'firebase-admin/app';
import { getDataConnect } from 'firebase-admin/data-connect';

// If you'd like to use OAuth2 flows and other credentials to log in,
// visit https://firebase.google.com/docs/admin/setup#initialize-sdk
// for alternative ways to initialize the SDK.

const app = initializeApp();

const dataConnect = getDataConnect({
    serviceId: 'serviceId',
    location: 'us-west2'
});

تصميم طلبات البحث وعمليات التعديل لاستخدامها مع Admin SDK

تكون Admin SDK مفيدة لتنفيذ عمليات Data Connect، مع مراعاة ما يلي:

فهم حزمة تطوير البرامج (SDK) وتوجيه التشغيل @auth(level: NO_ACCESS)

بما أنّ Admin SDK يعمل مع امتيازات، يمكنه تنفيذ أي من طلبات البحث والتعديلات بغض النظر عن مستويات الوصول التي تم ضبطها باستخدام توجيهات @auth، بما في ذلك مستوى NO_ACCESS.

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

استخدام حزمة تطوير البرامج (SDK) مع المحاكي Data Connect

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

تربط حِزم Firebase Admin SDK تلقائيًا بالمحاكي عند ضبط متغيّر البيئة DATA_CONNECT_EMULATOR_HOST:Data Connect

export DATA_CONNECT_EMULATOR_HOST="127.0.0.1:9399"

يمكنك الاطّلاع على ما يلي للحصول على مزيد من المعلومات:

تنفيذ عمليات المشرف

يتم توفير Admin SDK للعمليات ذات الامتيازات على بياناتك المهمة.

توفّر حزمة SDK للمشرف ثلاث مجموعات من واجهات برمجة التطبيقات:

  • حِزم SDK للمشرفين التي تم إنشاؤها، وهي حِزم SDK آمنة من حيث النوع تم إنشاؤها من gqlتعريفاتك بالطريقة نفسها التي تنشئ بها حِزم SDK للعملاء.
  • واجهة عامة لتنفيذ عمليات GraphQL عشوائية، حيث ينفّذ الرمز البرمجي الخاص بك الاستعلامات وعمليات التعديل ويرسلها إلى الطريقة executeGraphql للقراءة والكتابة أو الطريقة executeGraphqlRead للقراءة فقط.
  • واجهة متخصّصة لعمليات البيانات المجمّعة، تعرض بدلاً من طرق executeGraphql العامة طرقًا مخصّصة لعمليات التعديل: insert وinsertMany وupsert وupsertMany.

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

يمكنك إنشاء حِزم SDK للمشرف من تعريفات gql بالطريقة نفسها التي تنشئ بها حِزم 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). ويضمن ذلك أنّه يمكن فقط للمتصلين على مستوى المشرف تنفيذ هذه العمليات.

إدارة البيانات باستخدام طرق executeGraphql

إذا كنت بحاجة إلى تنفيذ عمليات لمرة واحدة لم تحدّد لها عمليات تعديل أو طلبات بحث gql، يمكنك استخدام الطريقة executeGraphql أو الطريقة executeGraphqlRead للقراءة فقط.

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

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

// Query to get posts, with authentication level PUBLIC
const queryGetPostsImpersonation = `
    query getPosts @auth(level: PUBLIC) {
        posts {
          description
        }
    }`;

// Attempt to access data as an unauthenticated user
const optionsUnauthenticated: GraphqlOptions<undefined> = {
    impersonate: {
        unauthenticated: true
    }
};

// executeGraphql with impersonated unauthenticated user scope
const gqlResponse = await dataConnect.executeGraphql<UserData, undefined>(queryGetPostsImpersonation, optionsUnauthenticated);

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

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

لاستخدام هذه الواجهة، اجمع المعلومات من رمز مميّز مخصّص للمصادقة باستخدام JWT يتّبع تنسيق الرمز المميز Authentication. يمكنك أيضًا الاطّلاع على دليل الرموز المميزة المخصّصة.

// Get the current user's data
const queryGetUserImpersonation = `
    query getUser @auth(level: USER) {
        user(key: {uid_expr: "auth.uid"}) {
            id,
            name
        }
    }`;

// Impersonate a user with the specified auth claims
const optionsAuthenticated: GraphqlOptions<undefined> = {
    impersonate: {
        authClaims: {
            sub: 'QVBJcy5ndXJ1'
        }
    }
};

// executeGraphql with impersonated authenticated user scope
const gqlResponse = await dataConnect.executeGraphql<UserData, undefined>(queryGetUserImpersonation, optionsAuthenticated);

// gqlResponse -> { "data": { "user": { "id": "QVBJcy5ndXJ1", "name": "Fred" } } }

استخدام بيانات اعتماد إدارية

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

// User can be publicly accessible, or restricted to admins
const query = "query getProfile(id: AuthID) { user(id: $id) { id name } }";

interface UserData {
  user: {
    id: string;
    name: string;
  };
}

export interface UserVariables {
  id: string;
}

const options:GraphqlOptions<UserVariables> = { variables: { id: "QVBJcy5ndXJ1" } };

// executeGraphql
const gqlResponse = await dataConnect.executeGraphql<UserData, UserVariables>(query, options);

// executeGraphqlRead (similar to previous sample but only for read operations)
const gqlResponse = await dataConnect.executeGraphqlRead<UserData, UserVariables>(query, options);

// gqlResponse -> { "data": { "user": { "id": "QVBJcy5ndXJ1", "name": "Fred" } } }

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

تنفيذ عمليات البيانات المجمّعة

تنصحك Firebase باستخدام Admin SDK لإجراء عمليات البيانات المجمّعة على قواعد البيانات المتاحة للاستخدام.

توفّر حزمة تطوير البرامج الطرق التالية للتعامل مع البيانات المجمّعة. من الوسيطات المقدَّمة، تنشئ كل طريقة عملية تعديل في GraphQL وتنفّذها.


// Methods of the bulk operations API
// dc is a Data Connect admin instance from getDataConnect

const resp = await dc.insert("movie" /*table name*/, data[0]);
const resp = await dc.insertMany("movie" /*table name*/, data);
const resp = await dc.upsert("movie" /*table name*/, data[0]);
const resp = await dc.upsertMany("movie" /*table name*/, data);

ملاحظات حول الأداء في العمليات المجمّعة

سيؤدي كل طلب إلى الخلفية إلى إجراء رحلة واحدة إلى Cloud SQL، لذا كلما زاد عدد الطلبات المجمّعة، زادت سرعة المعالجة.

ومع ذلك، كلما زاد حجم الدفعة، طالت عبارة SQL التي تم إنشاؤها. عند بلوغ الحد الأقصى لطول عبارة SQL في PostgreSQL، سيظهر لك خطأ.

في الواقع العملي، جرِّب أحجامًا مختلفة للعثور على حجم الدفعة المناسب لعبء العمل.

ما هي الخطوات التالية؟