בדיקת כללי אבטחה
במהלך פיתוח האפליקציה, יכול להיות שתרצו להגביל את הגישה למסד הנתונים של Firestore במצב Native. עם זאת, לפני ההשקה, תצטרכו כללי אבטחה מורכבים יותר ב-Firestore. באמצעות האמולטור של Firestore במצב Native, בנוסף ליצירת אב טיפוס ולבדיקה של התכונות וההתנהגות הכלליות של האפליקציה, אפשר לכתוב בדיקות יחידה שבודקות את ההתנהגות של כללי האבטחה של Firestore.
מדריך למתחילים
כדי לנסות כמה תרחישי בדיקה בסיסיים עם כללים פשוטים, אפשר להשתמש בדוגמה להפעלה מהירה.
הסבר על כללי אבטחה ב-Firestore
כדי לבצע אימות, הרשאה ואימות נתונים ללא שרת כשמשתמשים בספריות הלקוח לנייד ולאינטרנט, מטמיעים אימות ב-Firebase וכללי אבטחה של Firestore.
כללי האבטחה של Firestore כוללים שני חלקים:
matchהצהרה שמזהה מסמכים במסד הנתונים.allowביטוי שקובע את הגישה למסמכים האלה.
אימות ב-Firebase מאמת את פרטי הכניסה של המשתמשים ומספק את הבסיס למערכות גישה שמבוססות על משתמשים ותפקידים.
כל בקשה למסד נתונים מספריית לקוח לנייד או לאינטרנט של Firestore נבדקת מול כללי האבטחה לפני קריאה או כתיבה של נתונים. אם הכללים דוחים את הגישה לאחד מנתיבי המסמכים שצוינו, הבקשה כולה נכשלת.
מידע נוסף על כללי אבטחה ב-Firestore זמין במאמר תחילת העבודה עם כללי אבטחה ב-Firestore.
התקנת האמולטור
כדי להתקין את האמולטור של Firestore במצב Native, משתמשים ב-Firebase CLI ומריצים את הפקודה הבאה:
firebase setup:emulators:firestore
הרצת האמולטור
מתחילים בהפעלת פרויקט Firebase בספריית העבודה. זהו שלב ראשון נפוץ כשמשתמשים ב-Firebase CLI.
firebase init
מפעילים את האמולטור באמצעות הפקודה הבאה. האמולטור יפעל עד שתסיימו את התהליך:
firebase emulators:start --only firestore
במקרים רבים, רוצים להפעיל את האמולטור, להריץ חבילת מקרים לבדיקה ואז לכבות את האמולטור אחרי שהבדיקות רצות. אפשר לעשות את זה בקלות באמצעות הפקודה emulators:exec:
firebase emulators:exec --only firestore "./my-test-script.sh"
כשהאמולטור יופעל, הוא ינסה לפעול ביציאת ברירת מחדל (8080). אפשר לשנות את יציאת האמולטור על ידי שינוי הקטע "emulators" בקובץ firebase.json:
{
// ...
"emulators": {
"firestore": {
"port": "YOUR_PORT"
}
}
}לפני שמריצים את האמולטור
לפני שמתחילים להשתמש באמולטור, חשוב לזכור את הנקודות הבאות:
- האמולטור יטען בהתחלה את הכללים שצוינו בשדה
firestore.rulesבקובץfirebase.json. הוא מצפה לשם של קובץ מקומי שמכיל את כללי האבטחה של Firestore, ומחיל את הכללים האלה על כל הפרויקטים. אם לא תספקו את הנתיב של הקובץ המקומי או תשתמשו בשיטהloadFirestoreRulesכמו שמתואר בהמשך, האמולטור יתייחס לכל הפרויקטים כאילו יש להם כללי גישה פתוחים. - רוב ערכות ה-SDK של Firebase פועלות ישירות עם האמולטורים, אבל רק ספריית
@firebase/rules-unit-testingתומכת ב-mockingauthבכללי האבטחה, מה שמקל מאוד על בדיקות יחידה. בנוסף, בספרייה יש תמיכה בכמה תכונות ספציפיות לאמולטורים, כמו מחיקת כל הנתונים, כמו שמופיע בהמשך. - האמולטורים יקבלו גם טוקנים של Firebase Auth מהסביבה הפרודקטיבית שסופקו דרך Client SDKs, ויעריכו את הכללים בהתאם. כך תוכלו לקשר את האפליקציה ישירות לאמולטורים בבדיקות שילוב ובבדיקות ידניות.
הרצת בדיקות יחידה מקומיות
הרצת בדיקות יחידה מקומיות באמצעות JavaScript SDK בגרסה 9
Firebase מפיצה ספרייה לבדיקת יחידות של כללי אבטחה עם גרסה 9 של JavaScript SDK ועם גרסה 8 של SDK. ממשקי ה-API של הספרייה שונים באופן משמעותי. מומלץ להשתמש בספריית הבדיקות v9, שהיא יעילה יותר ודורשת פחות הגדרות כדי להתחבר לאמולטורים, וכך מאפשרת להימנע בבטחה משימוש לא מכוון במשאבי ייצור. כדי לשמור על תאימות לאחור, אנחנו ממשיכים להציע את ספריית הבדיקות v8.
משתמשים במודול @firebase/rules-unit-testing כדי ליצור אינטראקציה עם האמולטור שפועל באופן מקומי. אם מופיעות שגיאות של פסק זמן או שגיאות ECONNREFUSED, צריך לוודא שהאמולטור פועל.
מומלץ מאוד להשתמש בגרסה עדכנית של Node.js כדי שתוכלו להשתמש בסימון async/await. כמעט כל ההתנהגויות שתרצו לבדוק כוללות פונקציות אסינכרוניות, ומודול הבדיקה מיועד לעבודה עם קוד מבוסס-Promise.
ספריית בדיקות היחידה של כללים בגרסה 9 תמיד מודעת לאמולטורים, ולעולם לא תיגע במשאבי הייצור שלכם.
מייבאים את הספרייה באמצעות הצהרות ייבוא מודולריות של גרסה 9. לדוגמה:
import {
assertFails,
assertSucceeds,
initializeTestEnvironment
} from "@firebase/rules-unit-testing"
// Use `const { … } = require("@firebase/rules-unit-testing")` if imports are not supported
// Or we suggest `const testing = require("@firebase/rules-unit-testing")` if necessary.
אחרי הייבוא, הטמעה של בדיקות יחידה כוללת:
- יצירה והגדרה של
RulesTestEnvironmentעם קריאה אלinitializeTestEnvironment. - הגדרה של נתוני בדיקה בלי להפעיל כללים, באמצעות שיטה נוחה שמאפשרת לעקוף אותם באופן זמני,
RulesTestEnvironment.withSecurityRulesDisabled. - הגדרה של חבילת מקרים לבדיקה ושל פעולות לפני/אחרי כל בדיקה עם קריאות לניקוי נתוני הבדיקה והסביבה, כמו
RulesTestEnvironment.cleanup()אוRulesTestEnvironment.clearFirestore(). - הטמעה של תרחישי בדיקה שמדמים מצבי אימות באמצעות
RulesTestEnvironment.authenticatedContextו-RulesTestEnvironment.unauthenticatedContext.
שיטות נפוצות ופונקציות בסיסיות
אפשר גם לעיין בשיטות בדיקה ספציפיות לאמולטור ב-SDK בגרסה 9.
initializeTestEnvironment() => RulesTestEnvironment
הפונקציה הזו מאתחלת סביבת בדיקה לבדיקות יחידה של כללים. צריך להפעיל את הפונקציה הזו קודם כדי להגדיר את הבדיקה. כדי שההפעלה תתבצע בהצלחה, האמולטורים צריכים לפעול.
הפונקציה מקבלת אובייקט אופציונלי שמגדיר TestEnvironmentConfig, שיכול לכלול מזהה פרויקט והגדרות של אמולטור.
let testEnv = await initializeTestEnvironment({ projectId: "demo-project-1234", firestore: { rules: fs.readFileSync("firestore.rules", "utf8"), }, });
RulesTestEnvironment.authenticatedContext({ user_id: string, tokenOptions?: TokenOptions }) => RulesTestContext
השיטה הזו יוצרת RulesTestContext, שמתנהג כמו משתמש מאומת של Authentication. לבקשות שנוצרו באמצעות ההקשר שהוחזר יצורף טוקן אימות מדומה. אופציונלי: אפשר להעביר אובייקט שמגדיר טענות מותאמות אישית או שינויים בנתוני הטוקנים של האימות.
משתמשים באובייקט של הקשר הבדיקה שמוחזר בבדיקות כדי לגשת לכל מופעי האמולטור שהוגדרו, כולל אלה שהוגדרו באמצעות initializeTestEnvironment.
// Assuming a Firestore app and the Firestore emulator for this example import { setDoc } from "firebase/firestore"; const alice = testEnv.authenticatedContext("alice", { … }); // Use the Firestore instance associated with this context await assertSucceeds(setDoc(alice.firestore().doc('/users/alice'), { ... });
RulesTestEnvironment.unauthenticatedContext() => RulesTestContext
השיטה הזו יוצרת RulesTestContext, שמתנהג כמו לקוח שלא מחובר דרך אימות. לבקשות שנוצרות דרך ההקשר שמוחזר לא מצורפים אסימוני Firebase Auth.
משתמשים באובייקט של הקשר הבדיקה שמוחזר בבדיקות כדי לגשת לכל מופעי האמולטור שהוגדרו, כולל אלה שהוגדרו באמצעות initializeTestEnvironment.
// Assuming a Cloud Storage app and the Storage emulator for this example import { getStorage, ref, deleteObject } from "firebase/storage"; const alice = testEnv.unauthenticatedContext(); // Use the Cloud Storage instance associated with this context const desertRef = ref(alice.storage(), 'images/desert.jpg'); await assertSucceeds(deleteObject(desertRef));
RulesTestEnvironment.withSecurityRulesDisabled()
הפעלת פונקציית הגדרת בדיקה עם הקשר שמתנהג כאילו כללי האבטחה מושבתים.
השיטה הזו מקבלת פונקציית קריאה חוזרת שמקבלת את ההקשר של עקיפת כללי האבטחה ומחזירה אובייקט promise. ההקשר ייהרס ברגע שההבטחה תתקבל או תידחה.
RulesTestEnvironment.cleanup()
השיטה הזו מוחקת את כל RulesTestContexts שנוצרו בסביבת הבדיקה ומנקה את המשאבים הבסיסיים, וכך מאפשרת יציאה נקייה.
השיטה הזו לא משנה את מצב האמולטורים בשום צורה. כדי לאפס את הנתונים בין הבדיקות, משתמשים בשיטה לניקוי הנתונים שספציפית לאמולטור של האפליקציה.
assertSucceeds(pr: Promise<any>)) => Promise<any>
זוהי פונקציית כלי לבדיקת תרחישים.
הפונקציה קובעת שאובייקט ה-Promise שסופק, שעוטף פעולת אמולטור, יותאם ללא הפרות של כללי האבטחה.
await assertSucceeds(setDoc(alice.firestore(), '/users/alice'), { ... });assertFails(pr: Promise<any>)) => Promise<any>
זוהי פונקציית כלי לבדיקת תרחישים.
הפונקציה קובעת שאובייקט ה-Promise שסופק, שעוטף פעולת אמולטור, יידחה בגלל הפרה של כללי האבטחה.
await assertFails(setDoc(alice.firestore(), '/users/bob'), { ... });methods ספציפיות לאמולטור
אפשר גם לעיין בשיטות בדיקה נפוצות ופונקציות עזר ב-SDK בגרסה 9.
RulesTestEnvironment.clearFirestore() => Promise<void>
בשיטה הזו מוחקים נתונים במסד הנתונים של Firestore ששייכים ל-projectId שהוגדר לאמולטור של Firestore.
RulesTestContext.firestore(settings?: Firestore.FirestoreSettings) => Firestore;
השיטה הזו מקבלת מופע של Firestore עבור הקשר הבדיקה הזה. אפשר להשתמש במופע של Firebase JS Client SDK שמוחזר עם ממשקי API של Client SDK (מודולריים בגרסה 9 או תואמים בגרסה 9).
הדמיה של הערכות הכללים
האמולטור של Firestore במצב Native מאפשר לכם לראות את בקשות הלקוח בממשק המשתמש של כלים לאמולטור, כולל מעקב אחר הערכה של כללי האבטחה ב-Firebase.
פותחים את הכרטיסייה Firestore > בקשות כדי לראות את רצף ההערכה המפורט של כל בקשה.
יצירת דוחות בדיקה
אחרי שמריצים סדרה של בדיקות, אפשר לגשת לדוחות כיסוי של הבדיקות שבהם מוצגת הערכה של כל אחד מכללי האבטחה.
כדי לקבל את הדוחות, צריך להריץ שאילתה על נקודת קצה חשופה באמולטור. כדי להשתמש בגרסה שמתאימה לדפדפן, משתמשים בכתובת ה-URL הבאה:
http://localhost:8080/emulator/v1/projects/<project_id>:ruleCoverage.html
הפעולה הזו מפרקת את הכללים לביטויים ולביטויי משנה. אפשר להעביר את העכבר מעל הביטויים כדי לקבל מידע נוסף, כולל מספר ההערכות והערכים שמוחזרים. כדי לקבל את גרסת ה-JSON הגולמית של הנתונים האלה, צריך לכלול את כתובת ה-URL הבאה בשאילתה:
http://localhost:8080/emulator/v1/projects/<project_id>:ruleCoverage
ההבדלים בין האמולטור לבין סביבת הייצור
- לא צריך ליצור במפורש פרויקט של Firestore במצב Native. האמולטור יוצר באופן אוטומטי כל מופע שאליו ניגשים.
- האמולטור של Firestore במצב Native לא פועל עם תהליך האימות הרגיל של Firebase. במקום זאת, ב-Firebase Test SDK סיפקנו את השיטה
initializeTestApp()בספרייהrules-unit-testing, שמקבלת שדהauth. התנהגות הטיפול ב-Firebase שנוצר באמצעות השיטה הזו תהיה כאילו האימות בוצע בהצלחה בתור כל ישות שתספקו. אם תעבירו את הערךnull, ההתנהגות תהיה כאילו מדובר במשתמש לא מאומת (לדוגמה, כלליauth != nullייכשלו).
פתרון בעיות מוכרות
יכול להיות שתיתקלו בבעיות הבאות כשאתם משתמשים באמולטור של Firestore במצב Native. כדי לפתור בעיות בהתנהגות לא סדירה, כדאי לפעול לפי ההנחיות שבהמשך. ההערות האלה נכתבו בהתייחס לספריית בדיקות היחידה של כללי האבטחה, אבל הגישות הכלליות רלוונטיות לכל Firebase SDK.
התנהגות הבדיקה לא עקבית
אם הבדיקות עוברות ונכשלות מדי פעם, גם בלי שנעשו שינויים בבדיקות עצמן, יכול להיות שצריך לוודא שהן מסודרות ברצף הנכון.
רוב האינטראקציות עם האמולטור הן אסינכרוניות, לכן חשוב לוודא שכל הקוד האסינכרוני מסודר ברצף הנכון. כדי לתקן את הרצף, אפשר לשרשר הבטחות או להשתמש בסימון await באופן נרחב.
חשוב לעיין במיוחד בפעולות האסינכרוניות הבאות:
- הגדרת כללי אבטחה, למשל
initializeTestEnvironment. - קריאה וכתיבה של נתונים, למשל באמצעות
db.collection("users").doc("alice").get(). - טענות תפעוליות, כולל
assertSucceedsו-assertFails.
הבדיקות עוברות רק בפעם הראשונה שבה טוענים את האמולטור
האמולטור הוא stateful. הוא שומר בזיכרון את כל הנתונים שנכתבים בו, ולכן כל הנתונים אובדים בכל פעם שהאמולטור נסגר. אם מריצים כמה בדיקות עם אותו מזהה פרויקט, כל בדיקה יכולה להפיק נתונים שעשויים להשפיע על בדיקות עתידיות. אתם יכולים להשתמש באחת מהשיטות הבאות כדי לעקוף את ההתנהגות הזו:
- צריך להשתמש במזהי פרויקט ייחודיים לכל בדיקה. שימו לב שאם תבחרו לעשות את זה, תצטרכו להתקשר אל
initializeTestEnvironmentכחלק מכל בדיקה. הכללים נטענים אוטומטית רק עבור מזהה הפרויקט שמוגדר כברירת מחדל. - לשנות את המבנה של הבדיקות כך שלא תהיה אינטראקציה עם נתונים שנכתבו בעבר (לדוגמה, להשתמש באוסף נתונים שונה לכל בדיקה).
- מחיקה של כל הנתונים שנכתבו במהלך בדיקה.
הגדרת הבדיקה מסובכת מדי
כשמגדירים את הבדיקה, יכול להיות שתרצו לשנות נתונים באופן שלא מותר בפועל לפי כללי האבטחה של Firestore. אם הכללים מסבכים את הגדרת הבדיקה, נסו להשתמש ב-RulesTestEnvironment.withSecurityRulesDisabled בשלבי ההגדרה, כדי שפעולות קריאה וכתיבה לא יפעילו שגיאות PERMISSION_DENIED.
לאחר מכן, הבדיקה יכולה לבצע פעולות כמשתמש מאומת או לא מאומת באמצעות RulesTestEnvironment.authenticatedContext ו-unauthenticatedContext בהתאמה. כך תוכלו לוודא שכללי האבטחה של Firestore מאפשרים או חוסמים גישה למקרים שונים בצורה נכונה.