כתיבת תנאים לכללי האבטחה של Cloud Firestore

מדריך זה מתבסס על מדריך כללי האבטחה לבניית מבנה כדי להראות כיצד להוסיף תנאים לכללי האבטחה של Cloud Firestore. אם אינך מכיר את היסודות של כללי האבטחה של Cloud Firestore, עיין במדריך לתחילת העבודה .

אבן הבניין העיקרית של כללי האבטחה של Cloud Firestore הוא התנאי. תנאי הוא ביטוי בוליאני שקובע אם יש לאפשר או לדחות פעולה מסוימת. השתמש בכללי אבטחה כדי לכתוב תנאים הבודקים את אימות המשתמש, מאמתים נתונים נכנסים או אפילו גישה לחלקים אחרים במסד הנתונים שלך.

אימות

אחד מדפוסי כללי האבטחה הנפוצים ביותר הוא שליטה בגישה על סמך מצב האימות של המשתמש. לדוגמה, ייתכן שהאפליקציה שלך תרצה לאפשר רק למשתמשים מחוברים לכתוב נתונים:

service cloud.firestore {
  match /databases/{database}/documents {
    // Allow the user to access documents in the "cities" collection
    // only if they are authenticated.
    match /cities/{city} {
      allow read, write: if request.auth != null;
    }
  }
}

דפוס נפוץ נוסף הוא לוודא שמשתמשים יכולים לקרוא ולכתוב רק את הנתונים שלהם:

service cloud.firestore {
  match /databases/{database}/documents {
    // Make sure the uid of the requesting user matches name of the user
    // document. The wildcard expression {userId} makes the userId variable
    // available in rules.
    match /users/{userId} {
      allow read, update, delete: if request.auth != null && request.auth.uid == userId;
      allow create: if request.auth != null;
    }
  }
}

אם האפליקציה שלך משתמשת ב-Firebase Authentication או Google Cloud Identity Platform , המשתנה request.auth מכיל את פרטי האימות של הלקוח המבקש נתונים. למידע נוסף על request.auth , עיין בתיעוד ההפניה .

אימות מידע

אפליקציות רבות מאחסנות מידע בקרת גישה כשדות במסמכים במסד הנתונים. כללי האבטחה של Cloud Firestore יכולים לאפשר או לדחות גישה באופן דינמי על סמך נתוני מסמכים:

service cloud.firestore {
  match /databases/{database}/documents {
    // Allow the user to read data if the document has the 'visibility'
    // field set to 'public'
    match /cities/{city} {
      allow read: if resource.data.visibility == 'public';
    }
  }
}

משתנה resource מתייחס למסמך המבוקש, ו- resource.data היא מפה של כל השדות והערכים המאוחסנים במסמך. למידע נוסף על משתנה resource , עיין בתיעוד ההפניה .

בעת כתיבת נתונים, ייתכן שתרצה להשוות נתונים נכנסים לנתונים קיימים. במקרה זה, אם ערכת הכללים שלך מאפשרת את הכתיבה הממתינה, המשתנה request.resource מכיל את המצב העתידי של המסמך. עבור פעולות update שמשנות רק תת-קבוצה של שדות המסמך, המשתנה request.resource יכיל את מצב המסמך הממתין לאחר הפעולה. אתה יכול לבדוק את ערכי השדות ב- request.resource כדי למנוע עדכוני נתונים לא רצויים או לא עקביים:

service cloud.firestore {
  match /databases/{database}/documents {
    // Make sure all cities have a positive population and
    // the name is not changed
    match /cities/{city} {
      allow update: if request.resource.data.population > 0
                    && request.resource.data.name == resource.data.name;
    }
  }
}

גישה למסמכים אחרים

באמצעות הפונקציות get() ו- exists() , כללי האבטחה שלך יכולים להעריך בקשות נכנסות מול מסמכים אחרים במסד הנתונים. הפונקציות get() והפונקציות exists() מצפות לנתיבי מסמך שצוינו במלואם. בעת שימוש במשתנים לבניית נתיבים עבור get() ו- exists() , עליך להימלט במפורש למשתנים באמצעות התחביר $(variable) .

בדוגמה שלמטה, משתנה database נתפס על ידי משפט ההתאמה match /databases/{database}/documents ומשמש ליצירת הנתיב:

service cloud.firestore {
  match /databases/{database}/documents {
    match /cities/{city} {
      // Make sure a 'users' document exists for the requesting user before
      // allowing any writes to the 'cities' collection
      allow create: if request.auth != null && exists(/databases/$(database)/documents/users/$(request.auth.uid))

      // Allow the user to delete cities if their user document has the
      // 'admin' field set to 'true'
      allow delete: if request.auth != null && get(/databases/$(database)/documents/users/$(request.auth.uid)).data.admin == true
    }
  }
}

עבור כתיבה, אתה יכול להשתמש בפונקציה getAfter() כדי לגשת למצב של מסמך לאחר סיום עסקה או אצווה של כתיבה אך לפני שהטרנזקציה או האצווה מתבצעת. כמו get() , הפונקציה getAfter() לוקחת נתיב מסמך שצוין במלואו. אתה יכול להשתמש getAfter() כדי להגדיר קבוצות של כתיבה שחייבות להתרחש יחד כטרנזקציה או אצווה.

גישה למגבלות שיחות

יש מגבלה על קריאות גישה למסמכים לפי הערכת קבוצת כללים:

  • 10 עבור בקשות למסמך בודד ובקשות שאילתות.
  • 20 לקריאה מרובת מסמכים, עסקאות וכתיבת אצווה. המגבלה הקודמת של 10 חלה גם על כל פעולה.

    לדוגמה, דמיינו שאתם יוצרים בקשת כתיבה אצווה עם 3 פעולות כתיבה ושכללי האבטחה שלכם משתמשים ב-2 קריאות גישה למסמכים כדי לאמת כל כתיבה. במקרה זה, כל כתיבה משתמשת ב-2 מתוך 10 שיחות הגישה שלה ובקשת הכתיבה המצטברת משתמשת ב-6 מתוך 20 שיחות הגישה שלה.

חריגה משתי הגבלות גורמת לשגיאה שנדחתה. חלק משיחות הגישה למסמכים עשויות להיות מאוחסנות במטמון, ושיחות במטמון אינן נחשבות למגבלות.

להסבר מפורט על האופן שבו מגבלות אלו משפיעות על עסקאות וכתיבה אצווה, עיין במדריך לאבטחת פעולות אטומיות .

גישה לשיחות ותמחור

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

פונקציות מותאמות אישית

ככל שכללי האבטחה שלך הופכים מורכבים יותר, ייתכן שתרצה לעטוף קבוצות של תנאים בפונקציות שתוכל לעשות בהן שימוש חוזר בכל ערכת הכללים שלך. כללי אבטחה תומכים בפונקציות מותאמות אישית. התחביר של פונקציות מותאמות אישית דומה קצת ל-JavaScript, אבל פונקציות כללי אבטחה כתובות בשפה ספציפית לתחום שיש לה כמה מגבלות חשובות:

  • פונקציות יכולות להכיל רק הצהרת return אחת. הם לא יכולים להכיל שום היגיון נוסף. לדוגמה, הם לא יכולים לבצע לולאות או להתקשר לשירותים חיצוניים.
  • פונקציות יכולות לגשת אוטומטית לפונקציות ומשתנים מההיקף שבו הן מוגדרות. לדוגמה, לפונקציה המוגדרת בתוך היקף service cloud.firestore יש גישה למשתנה resource ולפונקציות מובנות כגון get() ו- exists() .
  • פונקציות עשויות לקרוא לפונקציות אחרות אך לא יחזרו. עומק ערימת השיחות הכולל מוגבל ל-10.
  • בגרסה v2 של כללים, פונקציות יכולות להגדיר משתנים באמצעות מילת המפתח let . לפונקציות יכולות להיות עד 10 כריכות ניתנות, אך עליהן להסתיים בהצהרת return.

פונקציה מוגדרת עם מילת המפתח function ולוקחת אפס או יותר ארגומנטים. לדוגמה, ייתכן שתרצה לשלב את שני סוגי התנאים המשמשים בדוגמאות לעיל לפונקציה אחת:

service cloud.firestore {
  match /databases/{database}/documents {
    // True if the user is signed in or the requested data is 'public'
    function signedInOrPublic() {
      return request.auth.uid != null || resource.data.visibility == 'public';
    }

    match /cities/{city} {
      allow read, write: if signedInOrPublic();
    }

    match /users/{user} {
      allow read, write: if signedInOrPublic();
    }
  }
}

השימוש בפונקציות בכללי האבטחה שלך הופך אותם לניתנים יותר לתחזוקה ככל שהמורכבות של הכללים שלך גדלה.

כללים אינם מסננים

לאחר שתאבטח את הנתונים שלך ותתחיל לכתוב שאילתות, זכור שכללי אבטחה אינם מסננים. אינך יכול לכתוב שאילתה עבור כל המסמכים באוסף ולצפות של Cloud Firestore להחזיר רק את המסמכים שאליהם יש ללקוח הנוכחי הרשאת גישה.

לדוגמה, קח את כלל האבטחה הבא:

service cloud.firestore {
  match /databases/{database}/documents {
    // Allow the user to read data if the document has the 'visibility'
    // field set to 'public'
    match /cities/{city} {
      allow read: if resource.data.visibility == 'public';
    }
  }
}

נדחה : כלל זה דוחה את השאילתה הבאה מכיוון שקבוצת התוצאות יכולה לכלול מסמכים שבהם visibility אינה public :

אינטרנט
db.collection("cities").get()
    .then(function(querySnapshot) {
        querySnapshot.forEach(function(doc) {
            console.log(doc.id, " => ", doc.data());
    });
});

מותר : כלל זה מאפשר את השאילתה הבאה מכיוון שהסעיף where("visibility", "==", "public") מבטיח שקבוצת התוצאות עומדת בתנאי הכלל:

אינטרנט
db.collection("cities").where("visibility", "==", "public").get()
    .then(function(querySnapshot) {
        querySnapshot.forEach(function(doc) {
            console.log(doc.id, " => ", doc.data());
        });
    });

כללי האבטחה של Cloud Firestore מעריכים כל שאילתה מול התוצאה הפוטנציאלית שלה ונכשלת בבקשה אם היא יכולה להחזיר מסמך שאין ללקוח הרשאה לקרוא. שאילתות חייבות לעמוד באילוצים שנקבעו על ידי כללי האבטחה שלך. למידע נוסף על כללי אבטחה ושאילתות, ראה שאילתת נתונים מאובטחת .

הצעדים הבאים