שימוש ב-SDK לאדמינים שנוצר

Firebase SQL Connect ערכות SDK לאדמינים מאפשרות לכם להפעיל את השאילתות והמוטציות שלכם מסביבות מהימנות כמו Cloud Functions, קצה עורפי בהתאמה אישית או תחנת עבודה משלכם. בדומה ליצירת ערכות SDK לאפליקציות לקוח, אתם יכולים ליצור במקביל ערכת SDK מותאמת אישית לאדמין כשאתם מתכננים את הסכימות, השאילתות והמוטציות שאתם פורסים בשירות SQL Connect. לאחר מכן, משלבים שיטות מתוך ערכת ה-SDK הזו בלוגיקה של ה-Backend או בסקריפטים של הניהול.

כמו שציינו במקומות אחרים, חשוב לדעת שSQL Connect שאילתות ומוטציות לא נשלחות על ידי לקוחות בזמן הבקשה. במקום זאת, כשפורסים את הפעולות של SQL Connect, הן מאוחסנות בשרת כמו Cloud Functions. המשמעות היא שבכל פעם שמבצעים שינויים בשאילתות ובמוטציות, צריך גם ליצור מחדש את ערכות ה-SDK של Admin ולפרוס מחדש את כל השירותים שמסתמכים עליהן.

לפני שמתחילים

  • מידע נוסף על עיצוב סכימות, שאילתות ומוטציות של SQL Connect בתהליך עבודה טיפוסי, מפתחים אותם במקביל לקוד האפליקציה, כולל שירותים שמשתמשים ב-SDK של Admin.
  • מתקינים את Firebase CLI.

  • כוללים את ה-SDK לאדמינים ל-Node.js כתלות בכל מקום שבו מתכננים לקרוא ל-SDK לאדמינים שנוצרו.

יצירה של Admin SDKs

אחרי שיוצרים את SQL 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.

    אם התקנתם את התוסף SQL Connect VS Code, הוא תמיד ידאג לעדכן את ערכות ה-SDK שנוצרו.

    אחרת, משתמשים ב-Firebase CLI:

    firebase dataconnect:sdk:generate

    לחלופין, כדי ליצור מחדש באופן אוטומטי את ערכות ה-SDK כשמעדכנים את הקבצים gql:

    firebase dataconnect:sdk:generate --watch

ביצוע פעולות מ-Admin SDK

ה-Admin 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 לאדמינים מיועד להרצה בסביבות מהימנות, ולכן יש לו גישה בלתי מוגבלת למסדי הנתונים.

כשמריצים פעולות ציבוריות באמצעות Admin SDK, מומלץ להימנע מהרצת הפעולה עם הרשאות אדמין מלאות (בהתאם לעיקרון של הרשאה מינימלית). במקום זאת, צריך להריץ את הפעולה כמשתמש שמתחזה למשתמש אחר (ראו את הקטע הבא) או כמשתמש לא מאומת שמתחזה למשתמש אחר. משתמשים לא מאומתים יכולים להריץ רק פעולות שמסומנות ב-PUBLIC.

בדוגמה שלמעלה, השאילתה getSongs מופעלת כמשתמש לא מאומת.

התחזות למשתמש

אפשר גם לבצע פעולות בשם משתמשים ספציפיים על ידי העברת חלק מאסימון Firebase Authentication או כולו באפשרות impersonate. לכל הפחות, צריך לציין את מזהה המשתמש של המשתמש בתביעת המשנה. (זהו אותו ערך כמו ערך השרת auth.uid שאפשר להפנות אליו בפעולות SQL Connect GraphQL).

כשמבצעים התחזות למשתמש, הפעולה תצליח רק אם נתוני המשתמש שסיפקתם יעברו את בדיקות האימות שצוינו בהגדרת GraphQL.

אם אתם קוראים ל-SDK שנוצר מנקודת קצה (endpoint) שנגישה לציבור, חשוב מאוד שנקודת הקצה תחייב אימות ושתוודאו את תקינות טוקן האימות לפני שאתם משתמשים בו כדי להתחזות למשתמש.

כשמשתמשים ב-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 } }
    );

    // ...
});

אחרת, צריך להשתמש בשיטה verifyIdToken של Admin SDK כדי לאמת ולפענח את טוקן האימות. לדוגמה, נניח שנקודת הקצה שלכם מיושמת כפונקציית 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). כך מבטיחים שרק מתקשרים ברמת אדמין יוכלו לבצע את הפעולות האלה.