Firebase Admin SDK הוא אוסף של ספריות שרת שמאפשרות לכם ליצור אינטראקציה עם Firebase מסביבות עם הרשאות מיוחדות כדי לבצע פעולות כמו הרצת שאילתות ושינויים בשירות Firebase SQL Connect לצורך ניהול נתונים בכמות גדולה ופעולות אחרות עם הרשאות מורחבות ופרטי כניסה של התחזות.
Admin SDK מספק לכם API להפעלת פעולות במצב קריאה/כתיבה ובמצב קריאה-בלבד. הפעולות לקריאה בלבד מאפשרות לכם לבצע פעולות ניהוליות שלא יכולות לשנות את הנתונים במסדי הנתונים שלכם.
הגדרת Admin SDK
כדי להתחיל להשתמש ב-Firebase SQL Connect בשרת, קודם צריך להתקין ולהגדיר את Admin SDK ל-Node.js.
אתחול Admin SDK בסקריפטים
כדי להפעיל את ה-SDK, מייבאים את התוספים SQL 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 שימושית להפעלת פעולות SQL Connect, בהתחשב בשיקולים הבאים.
הסבר על ה-SDK ועל @auth(level: NO_ACCESS) הוראות הפעולה
מכיוון ש-Admin SDK פועל עם הרשאות, הוא יכול להריץ כל שאילתה ומוטציה, ללא קשר לרמות הגישה שהוגדרו באמצעות הוראות @auth, כולל רמה NO_ACCESS.
אם אתם מארגנים את השאילתות והמוטציות האדמיניסטרטיביות שלכם בקובצי מקור .gql לייבוא לסקריפטים אדמיניסטרטיביים, בנוסף לפעולות הלקוח, מומלץ ב-Firebase לסמן את הפעולות האדמיניסטרטיביות ללא רמת גישה של הרשאה, או אולי להיות יותר מפורשים ולהגדיר אותן כ-NO_ACCESS. כך או כך, זה ימנע את ההרצה של פעולות כאלה מלקוחות או בהקשרים אחרים שאינם מורשים.
שימוש ב-SDK עם האמולטור SQL Connect
בסביבות אב-טיפוס ובסביבות בדיקה, יכול להיות שימושי לבצע פעולות כמו אתחול נתונים ופעולות אחרות על נתונים מחנויות מקומיות. ה-Admin SDK מאפשר לפשט את תהליכי העבודה כי הוא יכול להתעלם מאימות וממתן הרשאות בתהליכים מקומיים. (אפשר גם להביע הסכמה מפורשת לציות להגדרות האימות וההרשאה של הפעולות שלכם באמצעות התחברות זמנית כמשתמש אחר).
ערכות ה-SDK של Firebase לאדמינים מתחברות אוטומטית לSQL Connect
האמולטור כשמשתנה הסביבה DATA_CONNECT_EMULATOR_HOST מוגדר:
export DATA_CONNECT_EMULATOR_HOST="127.0.0.1:9399"
מידע נוסף זמין בדפים הבאים:
הרצת פעולות אדמין
ה-Admin SDK מסופק לפעולות עם הרשאות על הנתונים הקריטיים שלכם.
Admin SDK מספק שלוש קבוצות של ממשקי API:
- ערכות SDK לאדמין שנוצרות באופן אוטומטי, שהן ערכות SDK בטוחות לטיפוסים שנוצרות מההגדרות שלכם ב-
gqlבאותו אופן שבו אתם יוצרים ערכות SDK ללקוח. - ממשק כללי להפעלת פעולות שרירותיות של GraphQL, שבו הקוד שלכם מטמיע שאילתות ומוטציות ומעביר אותן לשיטה
executeGraphqlלקריאה ולכתיבה או לשיטהexecuteGraphqlReadלקריאה בלבד. - ממשק ייעודי לפעולות על נתונים בכמות גדולה, שבמקום שיטות
executeGraphqlכלליות, חושף שיטות ייעודיות לפעולות שינוי:insert,insertMany,upsertו-upsertMany.
ניהול נתונים באמצעות ערכות SDK שנוצרו
יוצרים SDK של Admin מתוך הגדרות gql באותו אופן שבו יוצרים 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 } }
);
// ...
});
אחרת, צריך להשתמש בשיטה 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 לקריאה בלבד.
ביצוע פעולות יחסיות מותאמות אישית (אחד לרבים) באמצעות executeGraphql
כשמפעילים פעולות מ-Admin SDK בסביבה עם הרשאות מיוחדות, לא צריך לציין את ההנחיה @allow במשתנים להוספות שטוחות רגילות (לא מקוננות) (כמו הוספה של רשומות נפרדות של סרט או שחקן).
עם זאת, כשמבצעים הוספות יחסיות מקוננות (למשל, הוספה של סרט יחד עם הביקורות הראשוניות שלו), עדיין צריך להצהיר על ההנחיה @allow בהגדרת המשתנה כדי לאפשר באופן סטטי את השדות היחסיים המקוננים בסכימת המשתנה שעברה קומפילציה.
// Custom GraphQL mutation with nested relational insert
const customMutation = `
mutation CustomBatchInsert(
$data: [Movie_Data!]!
@allow(fields: "title genre reviews_on_movie { rating reviewText }")
) {
movie_insertMany(data: $data)
}
`;
const variables = {
data: [
{
title: "Interstellar",
genre: "Sci-Fi",
reviews_on_movie: [
{
rating: 5,
reviewText: "Visually stunning and emotionally powerful.",
user: { id: "user-789" }
}
]
}
]
};
const response = await dataConnect.executeGraphql(customMutation, { variables });
התחזות למשתמש לא מאומת
כשמריצים פעולות ציבוריות באמצעות Admin 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 כדי לבצע פעולות על נתונים בכמות גדולה במסדי נתונים של ייצור.
ה-SDK מספק את השיטות הבאות לעבודה עם נתונים בכמות גדולה. מתוך הארגומנטים שסופקו, כל שיטה בונה ומבצעת מוטציה של GraphQL.
// Methods of the bulk operations API
// dc is a SQL 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);
פעולות יחסיות מוטמעות (אחד לרבים)
הפרמטר Admin SDK תומך בנתונים יחסיים בפעולות בכמות גדולה:
// Example of inserting a movie with nested reviews
const moviesData = [
{
title: "Interstellar",
genre: "Sci-Fi",
reviews_on_movie: [
{
rating: 5,
reviewText: "Visually stunning and emotionally powerful.",
user: { id: "user-789" }
}
]
}
];
// Atomically insert movies and their reviews in a single database round-trip.
const response = await dc.insertMany("movie", moviesData);
הערות לגבי ביצועים של פעולות בכמות גדולה
כל בקשה לשרת העורפי תגרום להעברה הלוך ושוב ל-Cloud SQL, לכן ככל שתשלחו יותר בקשות באצווה, כך התפוקה תהיה גבוהה יותר.
עם זאת, ככל שגודל האצווה גדול יותר, כך הצהרת ה-SQL שנוצרת ארוכה יותר. כשתגיעו למגבלת האורך של הצהרת ה-SQL ב-PostgreSQL, תיתקלו בשגיאה.
בפועל, כדאי לערוך ניסויים כדי למצוא את גודל האצווה המתאים לעומס העבודה.
מה השלב הבא?
- מידע על אכלוס מסדי נתונים בנתונים באמצעות Admin SDK
- כדאי לעיין בAPI של Admin SDK.
- משתמשים ב-CLI של Firebase ובמסוף Google Cloud לפעולות אחרות של ניהול פרויקטים, כמו ניהול סכימות ומחברים וניהול שירותים ומסדי נתונים.