שפת כללי אבטחה

כללי האבטחה של Firebase ממנפים שפות גמישות, חזקות ומותאמות אישית התומכות במגוון רחב של מורכבות ופירוט. אתה יכול להגדיר את הכללים שלך ספציפיים או כלליים ככל שהגיוני עבור האפליקציה שלך. חוקי מסד נתונים בזמן אמת משתמשים בתחביר שנראה כמו JavaScript במבנה JSON. כללי Cloud Firestore ו-Cloud Storage משתמשים בשפה המבוססת על שפת הביטוי Common (CEL) , שמתבססת על CEL עם match allow הצהרות התומכות בגישה מוענקת על תנאי.

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

בחר מוצר כדי ללמוד עוד על הכללים שלו.

מבנה בסיסי

Cloud Firestore

כללי האבטחה של Firebase ב-Cloud Firestore ו-Cloud Storage משתמשים במבנה ובתחביר הבאים:

service <<name>> {
  // Match the resource path.
  match <<path>> {
    // Allow the request if the following conditions are true.
    allow <<methods>> : if <<condition>>
  }
}

חשוב להבין את מושגי המפתח הבאים בעת בניית הכללים:

  • בקשה: השיטה או השיטות שהופעלו בהצהרת allow . אלו הן שיטות שאתה מאפשר להפעיל. השיטות הסטנדרטיות הן: get , list , create , update delete . שיטות נוחות read write מאפשרות גישת קריאה וכתיבה רחבה במסד הנתונים או נתיב האחסון שצוין.
  • נתיב: מסד הנתונים או מיקום האחסון, המיוצג כנתיב URI.
  • כלל: הצהרת allow , הכוללת תנאי שמתיר בקשה אם היא מוערכת כאמת.

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

אחסון בענן

כללי האבטחה של Firebase ב-Cloud Firestore ו-Cloud Storage משתמשים במבנה ובתחביר הבאים:

service <<name>> {
  // Match the resource path.
  match <<path>> {
    // Allow the request if the following conditions are true.
    allow <<methods>> : if <<condition>>
  }
}

חשוב להבין את מושגי המפתח הבאים בעת בניית הכללים:

  • בקשה: השיטה או השיטות שהופעלו בהצהרת allow . אלו הן שיטות שאתה מאפשר להפעיל. השיטות הסטנדרטיות הן: get , list , create , update delete . שיטות נוחות read write מאפשרות גישת קריאה וכתיבה רחבה במסד הנתונים או נתיב האחסון שצוין.
  • נתיב: מסד הנתונים או מיקום האחסון, המיוצג כנתיב URI.
  • כלל: הצהרת allow , הכוללת תנאי שמתיר בקשה אם היא מוערכת כאמת.

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

מסד נתונים בזמן אמת

במסד נתונים בזמן אמת, כללי האבטחה של Firebase מורכבים מביטויים דמויי JavaScript הכלולים במסמך JSON.

הם משתמשים בתחביר הבא:

{
  "rules": {
    "<<path>>": {
    // Allow the request if the condition for each method is true.
      ".read": <<condition>>,
      ".write": <<condition>>,
      ".validate": <<condition>>
    }
  }
}

ישנם שלושה מרכיבים בסיסיים בכלל:

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

בונה כללים

Cloud Firestore

המרכיבים הבסיסיים של כלל ב-Cloud Firestore ו-Cloud Storage הם כדלקמן:

  • הצהרת service : מצהירה על מוצר Firebase שהכללים חלים עליו.
  • בלוק match : מגדיר נתיב במסד הנתונים או בדלי האחסון שעליהם חלים הכללים.
  • הצהרת allow : מספקת תנאים למתן גישה, מובחנים לפי שיטות. השיטות הנתמכות כוללות: get , list , create , update , delete ושיטות הנוחות read write .
  • הצהרות אופציונליות function : מספקים את היכולת לשלב ולעטוף תנאים לשימוש על פני כללים מרובים.

service מכיל בלוק match אחד או יותר עם הצהרות allow המספקות תנאים המעניקים גישה לבקשות. משתני request resource זמינים לשימוש בתנאי כלל. שפת כללי האבטחה של Firebase תומכת גם בהצהרות function .

גרסת תחביר

הצהרת syntax מציינת את הגרסה של שפת הכללים של Firebase המשמשת לכתיבת המקור. הגרסה האחרונה של השפה היא v2 .

rules_version = '2';
service cloud.firestore {
...
}

אם לא מסופקת הצהרת rules_version , הכללים שלך יוערכו באמצעות מנוע v1 .

שֵׁרוּת

הצהרת service מגדירה על איזה מוצר או שירות של Firebase חלים הכללים שלך. אתה יכול לכלול רק הצהרת service אחת לכל קובץ מקור.

Cloud Firestore

service cloud.firestore {
 // Your 'match' blocks with their corresponding 'allow' statements and
 // optional 'function' declarations are contained here
}

אחסון בענן

service firebase.storage {
  // Your 'match' blocks with their corresponding 'allow' statements and
  // optional 'function' declarations are contained here
}

אם אתה מגדיר כללים עבור Cloud Firestore ו-Cloud Storage באמצעות Firebase CLI, תצטרך לשמור אותם בקבצים נפרדים.

התאמה

בלוק match מכריז על דפוס path המותאם לנתיב עבור הפעולה המבוקשת (ה- request.path הנכנס). גוף match חייב לכלול בלוק match מקונן אחד או יותר, הצהרות allow או הצהרות function . הנתיב בבלוקים של match מקוננת הוא יחסי לנתיב בבלוק match האב.

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

התאמות מול תבנית path עשויות להיות חלקיות או שלמות:

  • התאמות חלקיות: תבנית path היא התאמה קידומת של request.path .
  • התאמות שלמות: תבנית path תואמת לכל request.path .

כאשר מתבצעת התאמה מלאה , הכללים בתוך הבלוק מוערכים. כאשר מתבצעת התאמה חלקית , כללי match המקוננת נבדקים כדי לראות אם path מקונן כלשהו ישלים את ההתאמה.

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

// Given request.path == /example/hello/nested/path the following
// declarations indicate whether they are a partial or complete match and
// the value of any variables visible within the scope.
service firebase.storage {
  // Partial match.
  match /example/{singleSegment} {   // `singleSegment` == 'hello'
    allow write;                     // Write rule not evaluated.
    // Complete match.
    match /nested/path {             // `singleSegment` visible in scope.
      allow read;                    // Read rule is evaluated.
    }
  }
  // Complete match.
  match /example/{multiSegment=**} { // `multiSegment` == /hello/nested/path
    allow read;                      // Read rule is evaluated.
  }
}

כפי שמראה הדוגמה למעלה, הצהרות path תומכות במשתנים הבאים:

  • תו כללי של מקטע יחיד: משתנה תו כללי מוכרז בנתיב על ידי גלישת משתנה בסוגריים מסולסלים: {variable} . משתנה זה נגיש בתוך הצהרת match string .
  • תו כללי רקורסיבי: התו הכללי הרקורסי, או רב-מקטע, מתאים למספר מקטעי נתיב בנתיב או מתחתיו. תו כללי זה מתאים לכל הנתיבים מתחת למיקום שהגדרת אותו. אתה יכול להכריז על זה על ידי הוספת המחרוזת =** בסוף משתנה הפלח שלך: {variable=**} . משתנה זה נגיש בתוך הצהרת match כאובייקט path .

להתיר

בלוק match מכיל הצהרת allow אחת או יותר. אלה הכללים האמיתיים שלך. אתה יכול להחיל כללי allow על שיטה אחת או יותר. התנאים בהצהרת allow חייבים להעריך כאמת כדי ש-Cloud Firestore או Cloud Storage ייענו לכל בקשה נכנסת. אתה יכול גם לכתוב הצהרות allow ללא תנאים, לדוגמה, allow read . אם הצהרת allow לא כוללת תנאי, עם זאת, היא תמיד מאפשרת את הבקשה לשיטה זו.

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

שקול את הדוגמה הבאה, שבה כל משתמש יכול לקרוא או למחוק כל אחד מהקבצים שלו. כלל מפורט יותר מאפשר כתיבה רק אם המשתמש המבקש את הכתיבה הוא הבעלים של הקובץ והקובץ הוא PNG. משתמש יכול למחוק כל קובץ בנתיב המשנה - גם אם הם לא PNGs - מכיוון שהכלל הקודם מאפשר זאת.

service firebase.storage {
  // Allow the requestor to read or delete any resource on a path under the
  // user directory.
  match /users/{userId}/{anyUserFile=**} {
    allow read, delete: if request.auth != null && request.auth.uid == userId;
  }

  // Allow the requestor to create or update their own images.
  // When 'request.method' == 'delete' this rule and the one matching
  // any path under the user directory would both match and the `delete`
  // would be permitted.

  match /users/{userId}/images/{imageId} {
    // Whether to permit the request depends on the logical OR of all
    // matched rules. This means that even if this rule did not explicitly
    // allow the 'delete' the earlier rule would have.
    allow write: if request.auth != null && request.auth.uid == userId && imageId.matches('*.png');
  }
}

שיטה

כל הצהרת allow כוללת שיטה המעניקה גישה לבקשות נכנסות מאותה שיטה.

שיטה סוג הבקשה
שיטות נוחות
read כל סוג של בקשת קריאה
write כל סוג של בקשת כתיבה
שיטות סטנדרטיות
get קרא בקשות למסמכים או קבצים בודדים
list קרא בקשות לשאילתות ואוספים
create כתוב מסמכים או קבצים חדשים
update כתוב למסמכי מסד נתונים קיימים או עדכן מטא נתונים של קבצים
delete מחק נתונים

לא ניתן לחפוף שיטות קריאה באותו בלוק match או שיטות כתיבה סותרות באותה הצהרת path .

לדוגמה, הכללים הבאים ייכשלו:

service bad.example {
  match /rules/with/overlapping/methods {
    // This rule allows reads to all authenticated users
    allow read: if request.auth != null;

    match another/subpath {
      // This secondary, more specific read rule causes an error
      allow get: if request.auth != null && request.auth.uid == "me";
      // Overlapping write methods in the same path cause an error as well
      allow write: if request.auth != null;
      allow create: if request.auth != null && request.auth.uid == "me";
    }
  }
}

פוּנקצִיָה

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

  • פונקציות יכולות להכיל רק הצהרת return אחת. הם לא יכולים להכיל שום היגיון נוסף. לדוגמה, הם לא יכולים לבצע לולאות או להתקשר לשירותים חיצוניים.
  • פונקציות יכולות לגשת אוטומטית לפונקציות ומשתנים מההיקף שבו הן מוגדרות. לדוגמה, לפונקציה המוגדרת בתוך היקף service cloud.firestore יש גישה למשתנה resource ולפונקציות מובנות כגון get() ו- exists() .
  • פונקציות עשויות לקרוא לפונקציות אחרות אך לא יחזרו. עומק ערימת השיחות הכולל מוגבל ל-20.
  • בגרסה 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();
    }
  }
}

להלן דוגמה המציגה ארגומנטים של פונקציות והקצאות תן. יש להפריד בין הצהרות מטלות בנקודה-פסיק.

function isAuthorOrAdmin(userId, article) {
  let isAuthor = article.author == userId;
  let isAdmin = exists(/databases/$(database)/documents/admins/$(userId));
  return isAuthor || isAdmin;
}

שים לב כיצד הקצאת isAdmin אוכפת חיפוש של אוסף המנהלים. להערכה עצלנית ללא צורך בחיפושים מיותרים, נצל את האופי הקצר של && (AND) ו- || (OR) השוואות לקריאת פונקציה שנייה רק ​​אם הוצג isAuthor כנכון (עבור && השוואות) או לא נכון (עבור || השוואות).

function isAdmin(userId) {
  return exists(/databases/$(database)/documents/admins/$(userId));
}
function isAuthorOrAdmin(userId, article) {
  let isAuthor = article.author == userId;
  // `||` is short-circuiting; isAdmin called only if isAuthor == false.
  return isAuthor || isAdmin(userId);
}

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

אחסון בענן

המרכיבים הבסיסיים של כלל ב-Cloud Firestore ו-Cloud Storage הם כדלקמן:

  • הצהרת service : מצהירה על מוצר Firebase שהכללים חלים עליו.
  • בלוק match : מגדיר נתיב במסד הנתונים או בדלי האחסון שעליהם חלים הכללים.
  • הצהרת allow : מספקת תנאים למתן גישה, מובחנים לפי שיטות. השיטות הנתמכות כוללות: get , list , create , update , delete ושיטות הנוחות read write .
  • הצהרות אופציונליות function : מספקים את היכולת לשלב ולעטוף תנאים לשימוש על פני כללים מרובים.

service מכיל בלוק match אחד או יותר עם הצהרות allow המספקות תנאים המעניקים גישה לבקשות. משתני request resource זמינים לשימוש בתנאי כלל. שפת כללי האבטחה של Firebase תומכת גם בהצהרות function .

גרסת תחביר

הצהרת syntax מציינת את הגרסה של שפת הכללים של Firebase המשמשת לכתיבת המקור. הגרסה האחרונה של השפה היא v2 .

rules_version = '2';
service cloud.firestore {
...
}

אם לא מסופקת הצהרת rules_version , הכללים שלך יוערכו באמצעות מנוע v1 .

שֵׁרוּת

הצהרת service מגדירה על איזה מוצר או שירות של Firebase חלים הכללים שלך. אתה יכול לכלול רק הצהרת service אחת לכל קובץ מקור.

Cloud Firestore

service cloud.firestore {
 // Your 'match' blocks with their corresponding 'allow' statements and
 // optional 'function' declarations are contained here
}

אחסון בענן

service firebase.storage {
  // Your 'match' blocks with their corresponding 'allow' statements and
  // optional 'function' declarations are contained here
}

אם אתה מגדיר כללים עבור Cloud Firestore ו-Cloud Storage באמצעות Firebase CLI, תצטרך לשמור אותם בקבצים נפרדים.

התאמה

בלוק match מכריז על דפוס path המותאם לנתיב עבור הפעולה המבוקשת (ה- request.path הנכנס). גוף match חייב לכלול בלוק match מקונן אחד או יותר, הצהרות allow או הצהרות function . הנתיב בבלוקים של match מקוננת הוא יחסי לנתיב בבלוק match האב.

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

התאמות מול תבנית path עשויות להיות חלקיות או שלמות:

  • התאמות חלקיות: תבנית path היא התאמה קידומת של request.path .
  • התאמות שלמות: תבנית path תואמת לכל request.path .

כאשר מתבצעת התאמה מלאה , הכללים בתוך הבלוק מוערכים. כאשר מתבצעת התאמה חלקית , כללי match המקוננת נבדקים כדי לראות אם path מקונן כלשהו ישלים את ההתאמה.

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

// Given request.path == /example/hello/nested/path the following
// declarations indicate whether they are a partial or complete match and
// the value of any variables visible within the scope.
service firebase.storage {
  // Partial match.
  match /example/{singleSegment} {   // `singleSegment` == 'hello'
    allow write;                     // Write rule not evaluated.
    // Complete match.
    match /nested/path {             // `singleSegment` visible in scope.
      allow read;                    // Read rule is evaluated.
    }
  }
  // Complete match.
  match /example/{multiSegment=**} { // `multiSegment` == /hello/nested/path
    allow read;                      // Read rule is evaluated.
  }
}

כפי שמראה הדוגמה למעלה, הצהרות path תומכות במשתנים הבאים:

  • תו כללי של מקטע יחיד: משתנה תו כללי מוכרז בנתיב על ידי גלישת משתנה בסוגריים מסולסלים: {variable} . משתנה זה נגיש בתוך הצהרת match string .
  • תו כללי רקורסיבי: התו הכללי הרקורסי, או רב-מקטע, מתאים למספר מקטעי נתיב בנתיב או מתחתיו. תו כללי זה מתאים לכל הנתיבים מתחת למיקום שהגדרת אותו. אתה יכול להכריז על זה על ידי הוספת המחרוזת =** בסוף משתנה הפלח שלך: {variable=**} . משתנה זה נגיש בתוך הצהרת match כאובייקט path .

להתיר

בלוק match מכיל הצהרת allow אחת או יותר. אלה הכללים האמיתיים שלך. אתה יכול להחיל כללי allow על שיטה אחת או יותר. התנאים בהצהרת allow חייבים להעריך כאמת כדי ש-Cloud Firestore או Cloud Storage ייענו לכל בקשה נכנסת. אתה יכול גם לכתוב הצהרות allow ללא תנאים, לדוגמה, allow read . אם הצהרת allow לא כוללת תנאי, עם זאת, היא תמיד מאפשרת את הבקשה לשיטה זו.

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

שקול את הדוגמה הבאה, שבה כל משתמש יכול לקרוא או למחוק כל אחד מהקבצים שלו. כלל מפורט יותר מאפשר כתיבה רק אם המשתמש המבקש את הכתיבה הוא הבעלים של הקובץ והקובץ הוא PNG. משתמש יכול למחוק כל קובץ בנתיב המשנה - גם אם הם לא PNGs - מכיוון שהכלל הקודם מאפשר זאת.

service firebase.storage {
  // Allow the requestor to read or delete any resource on a path under the
  // user directory.
  match /users/{userId}/{anyUserFile=**} {
    allow read, delete: if request.auth != null && request.auth.uid == userId;
  }

  // Allow the requestor to create or update their own images.
  // When 'request.method' == 'delete' this rule and the one matching
  // any path under the user directory would both match and the `delete`
  // would be permitted.

  match /users/{userId}/images/{imageId} {
    // Whether to permit the request depends on the logical OR of all
    // matched rules. This means that even if this rule did not explicitly
    // allow the 'delete' the earlier rule would have.
    allow write: if request.auth != null && request.auth.uid == userId && imageId.matches('*.png');
  }
}

שיטה

כל הצהרת allow כוללת שיטה המעניקה גישה לבקשות נכנסות מאותה שיטה.

שיטה סוג הבקשה
שיטות נוחות
read כל סוג של בקשת קריאה
write כל סוג של בקשת כתיבה
שיטות סטנדרטיות
get קרא בקשות למסמכים או קבצים בודדים
list קרא בקשות לשאילתות ואוספים
create כתוב מסמכים או קבצים חדשים
update כתוב למסמכי מסד נתונים קיימים או עדכן מטא נתונים של קבצים
delete מחק נתונים

לא ניתן לחפוף שיטות קריאה באותו בלוק match או שיטות כתיבה סותרות באותה הצהרת path .

לדוגמה, הכללים הבאים ייכשלו:

service bad.example {
  match /rules/with/overlapping/methods {
    // This rule allows reads to all authenticated users
    allow read: if request.auth != null;

    match another/subpath {
      // This secondary, more specific read rule causes an error
      allow get: if request.auth != null && request.auth.uid == "me";
      // Overlapping write methods in the same path cause an error as well
      allow write: if request.auth != null;
      allow create: if request.auth != null && request.auth.uid == "me";
    }
  }
}

פוּנקצִיָה

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

  • פונקציות יכולות להכיל רק הצהרת return אחת. הם לא יכולים להכיל שום היגיון נוסף. לדוגמה, הם לא יכולים לבצע לולאות או להתקשר לשירותים חיצוניים.
  • פונקציות יכולות לגשת אוטומטית לפונקציות ומשתנים מההיקף שבו הן מוגדרות. לדוגמה, לפונקציה המוגדרת בתוך היקף service cloud.firestore יש גישה למשתנה resource ולפונקציות מובנות כגון get() ו- exists() .
  • פונקציות עשויות לקרוא לפונקציות אחרות אך לא יחזרו. עומק ערימת השיחות הכולל מוגבל ל-20.
  • בגרסה 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();
    }
  }
}

להלן דוגמה המציגה ארגומנטים של פונקציות והקצאות תן. יש להפריד בין הצהרות מטלות בנקודה-פסיק.

function isAuthorOrAdmin(userId, article) {
  let isAuthor = article.author == userId;
  let isAdmin = exists(/databases/$(database)/documents/admins/$(userId));
  return isAuthor || isAdmin;
}

שים לב כיצד הקצאת isAdmin אוכפת חיפוש של אוסף המנהלים. להערכה עצלנית ללא צורך בחיפושים מיותרים, נצל את האופי הקצר של && (AND) ו- || (OR) השוואות לקריאת פונקציה שנייה רק ​​אם הוצג isAuthor כנכון (עבור && השוואות) או לא נכון (עבור || השוואות).

function isAdmin(userId) {
  return exists(/databases/$(database)/documents/admins/$(userId));
}
function isAuthorOrAdmin(userId, article) {
  let isAuthor = article.author == userId;
  // `||` is short-circuiting; isAdmin called only if isAuthor == false.
  return isAuthor || isAdmin(userId);
}

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

מסד נתונים בזמן אמת

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

מיקום מסד הנתונים

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

  {
    "messages": {
      "message0": {
        "content": "Hello",
        "timestamp": 1405704370369
      },
      "message1": {
        "content": "Goodbye",
        "timestamp": 1405704395231
      },
      ...
    }
  }

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

  {
    "rules": {
      "messages": {
        "$message": {
          // only messages from the last ten minutes can be read
          ".read": "data.child('timestamp').val() > (now - 600000)",

          // new messages must have a string content and a number timestamp
          ".validate": "newData.hasChildren(['content', 'timestamp']) &&
                        newData.child('content').isString() &&
                        newData.child('timestamp').isNumber()"
        }
      }
    }
  }

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

  {
    "rules": {
      "rooms": {
        // This rule applies to any child of /rooms/, the key for each room id
        // is stored inside $room_id variable for reference
        "$room_id": {
          "topic": {
            // The room's topic can be changed if the room id has "public" in it
            ".write": "$room_id.contains('public')"
          }
        }
      }
    }
  }

אתה יכול גם להשתמש $variable במקביל לשמות נתיבים קבועים.

  {
    "rules": {
      "widget": {
        // a widget can have a title or color attribute
        "title": { ".validate": true },
        "color": { ".validate": true },

        // but no other child paths are allowed
        // in this case, $other means any key excluding "title" and "color"
        "$other": { ".validate": false }
      }
    }
  }

שיטה

במסד נתונים בזמן אמת, ישנם שלושה סוגים של כללים. שניים מסוגי כללים אלה - read write - חלים על השיטה של ​​בקשה נכנסת. סוג כלל validate אוכף מבני נתונים ומאמת את הפורמט והתוכן של הנתונים. כללים מפעילים כללי .validate לאחר וידוא שכלל .write מעניק גישה.

סוגי כללים
.לקרוא מתאר אם ומתי מותר לקרוא נתונים על ידי משתמשים.
.לִכתוֹב מתאר אם ומתי מותר לכתוב נתונים.
.לְאַמֵת מגדיר כיצד ייראה ערך בפורמט נכון, האם יש לו תכונות צאצא וסוג הנתונים.

כברירת מחדל, אם אין כלל המאפשר זאת, הגישה בנתיב נדחית.

תנאי בנייה

Cloud Firestore

תנאי הוא ביטוי בוליאני שקובע אם יש לאפשר או לדחות פעולה מסוימת. משתני request resource מספקים הקשר לתנאים אלה.

משתנה request

משתנה request כולל את השדות הבאים ומידע מתאים:

request.auth

JSON Web Token (JWT) המכיל אישורי אימות מאימות Firebase. auth token מכיל קבוצה של תביעות סטנדרטיות וכל תביעות מותאמות אישית שאתה יוצר באמצעות אימות Firebase. למידע נוסף על כללי אבטחה ואימות של Firebase .

request.method

ה- request.method עשויה להיות כל אחת מהשיטות הסטנדרטיות או שיטה מותאמת אישית. שיטות הנוחות read write קיימות גם כדי לפשט את כללי הכתיבה החלים על כל השיטות הסטנדרטיות לקריאה בלבד או על כל שיטות הכתיבה בלבד, בהתאמה.

request.params

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

request.path

ה- request.path הוא הנתיב עבור resource היעד. הדרך היא יחסית לשירות. קטעי נתיב המכילים תווים בטוחים שאינם כתובות אתרים כגון / מקודדים ב-url.

משתנה resource

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

מפעילים וקדימות מפעילים

השתמש בטבלה שלהלן כהתייחסות למפעילים ובעדיפותם המתאימה בכללים עבור Cloud Firestore ו-Cloud Storage.

בהינתן ביטויים שרירותיים a ו- b , שדה f , ואינדקס i .

מַפעִיל תיאור אסוציאטיביות
a[i] a() af אינדקס, שיחה, גישה לשדה משמאל לימין
!a -a שלילה לא נורית מימין לשמאל
a/ba%ba*b אופרטורים כפולים משמאל לימין
a+b ab מפעילי תוספים משמאל לימין
a>ba>=ba מפעילים יחסיים משמאל לימין
a in b קיום ברשימה או במפה משמאל לימין
a is type השוואת סוגים, כאשר type יכול להיות bool, int, float, number, מחרוזת, רשימה, מפה, חותמת זמן, משך, נתיב או latlng משמאל לימין
a==ba!=b מפעילי השוואה משמאל לימין
a && b AND מותנה משמאל לימין
a || b OR מותנה משמאל לימין
a ? true_value : false_value ביטוי טרנרי משמאל לימין

אחסון בענן

תנאי הוא ביטוי בוליאני שקובע אם יש לאפשר או לדחות פעולה מסוימת. משתני request resource מספקים הקשר לתנאים אלה.

משתנה request

משתנה request כולל את השדות הבאים ומידע מתאים:

request.auth

JSON Web Token (JWT) המכיל אישורי אימות מאימות Firebase. auth token מכיל קבוצה של תביעות סטנדרטיות וכל תביעות מותאמות אישית שאתה יוצר באמצעות אימות Firebase. למידע נוסף על כללי אבטחה ואימות של Firebase .

request.method

ה- request.method עשויה להיות כל אחת מהשיטות הסטנדרטיות או שיטה מותאמת אישית. שיטות הנוחות read write קיימות גם כדי לפשט את כללי הכתיבה החלים על כל השיטות הסטנדרטיות לקריאה בלבד או על כל שיטות הכתיבה בלבד, בהתאמה.

request.params

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

request.path

ה- request.path הוא הנתיב עבור resource היעד. הדרך היא יחסית לשירות. קטעי נתיב המכילים תווים בטוחים שאינם כתובות אתרים כגון / מקודדים ב-url.

משתנה resource

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

מפעילים וקדימות מפעילים

השתמש בטבלה שלהלן כהתייחסות למפעילים ובעדיפותם המתאימה בכללים עבור Cloud Firestore ו-Cloud Storage.

בהינתן ביטויים שרירותיים a ו- b , שדה f , ואינדקס i .

מַפעִיל תיאור אסוציאטיביות
a[i] a() af אינדקס, שיחה, גישה לשדה משמאל לימין
!a -a שלילה לא נורית מימין לשמאל
a/ba%ba*b אופרטורים כפולים משמאל לימין
a+b ab מפעילי תוספים משמאל לימין
a>ba>=ba מפעילים יחסיים משמאל לימין
a in b קיום ברשימה או במפה משמאל לימין
a is type השוואת סוגים, כאשר type יכול להיות bool, int, float, number, מחרוזת, רשימה, מפה, חותמת זמן, משך, נתיב או latlng משמאל לימין
a==ba!=b מפעילי השוואה משמאל לימין
a && b AND מותנה משמאל לימין
a || b OR מותנה משמאל לימין
a ? true_value : false_value ביטוי טרנרי משמאל לימין

מסד נתונים בזמן אמת

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

משתנים מוגדרים מראש

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

משתנים מוגדרים מראש
עַכשָׁיו הזמן הנוכחי באלפיות שניות מאז עידן לינוקס. זה עובד טוב במיוחד עבור אימות חותמות זמן שנוצרו עם ה-SDK של firebase.database.ServerValue.TIMESTAMP.
שורש RuleDataSnapshot המייצג את נתיב הבסיס במסד הנתונים של Firebase כפי שהוא קיים לפני ניסיון הפעולה.
מידע חדש RuleDataSnapshot המייצג את הנתונים כפי שהם יהיו קיימים לאחר ניסיון הפעולה. הוא כולל את הנתונים החדשים הנכתבים ואת הנתונים הקיימים.
נתונים RuleDataSnapshot המייצג את הנתונים כפי שהיו קיימים לפני ניסיון הפעולה.
משתני $ נתיב תווים כלליים המשמשים לייצוג מזהים ומפתחות צאצאים דינמיים.
אישור מייצג את מטען האסימון של משתמש מאומת.

ניתן להשתמש במשתנים אלה בכל מקום בכללים שלך. לדוגמה, כללי האבטחה שלהלן מבטיחים שהנתונים הנכתבים לצומת /foo/ חייבים להיות מחרוזת בת פחות מ-100 תווים:

{
  "rules": {
    "foo": {
      // /foo is readable by the world
      ".read": true,

      // /foo is writable by the world
      ".write": true,

      // data written to /foo must be a string less than 100 characters
      ".validate": "newData.isString() && newData.val().length < 100"
    }
  }
}

כללים מבוססי נתונים

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

שקול את הדוגמה הזו, המאפשרת פעולות כתיבה כל עוד הערך של הצומת /allow_writes/ true , לצומת האב אין ערכת דגל readOnly , ויש ילד בשם foo בנתונים החדשים שנכתבו:

".write": "root.child('allow_writes').val() === true &&
          !data.parent().child('readOnly').exists() &&
          newData.child('foo').exists()"

כללים מבוססי שאילתה

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

לדוגמה, הכלל הבא המבוסס על שאילתות משתמש בכללי אבטחה מבוססי משתמשים ובכללים מבוססי שאילתות כדי להגביל את הגישה לנתונים באוסף baskets רק לסל הקניות שבבעלות המשתמש הפעיל:

"baskets": {
  ".read": "auth.uid !== null &&
            query.orderByChild === 'owner' &&
            query.equalTo === auth.uid" // restrict basket access to owner of basket
}

השאילתה הבאה, הכוללת את פרמטרי השאילתה בכלל, תצליח:

db.ref("baskets").orderByChild("owner")
                 .equalTo(auth.currentUser.uid)
                 .on("value", cb)                 // Would succeed

עם זאת, שאילתות שאינן כוללות את הפרמטרים בכלל ייכשלו עם שגיאה PermissionDenied :

db.ref("baskets").on("value", cb)                 // Would fail with PermissionDenied

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

לדוגמה, הכלל הבא מגביל את גישת הקריאה רק ל-1000 התוצאות הראשונות של שאילתה, לפי סדר עדיפות:

messages: {
  ".read": "query.orderByKey &&
            query.limitToFirst <= 1000"
}

// Example queries:

db.ref("messages").on("value", cb)                // Would fail with PermissionDenied

db.ref("messages").limitToFirst(1000)
                  .on("value", cb)                // Would succeed (default order by key)

query. ביטויים זמינים בכללי האבטחה של מסד נתונים בזמן אמת.

ביטויי כלל מבוססי שאילתה
ביטוי סוּג תיאור
query.orderByKey
query.orderByPriority
query.orderByValue
בוליאני נכון עבור שאילתות מסודרות לפי מפתח, עדיפות או ערך. שקר אחרת.
query.orderByChild חוּט
ריק
השתמש במחרוזת כדי לייצג את הנתיב היחסי לצומת צאצא. לדוגמה, query.orderByChild === "address/zip" . אם השאילתה לא מסודרת על ידי צומת צאצא, ערך זה הוא null.
query.startAt
query.endAt
query.equalTo
חוּט
מספר
בוליאני
ריק
מאחזר את הגבולות של השאילתה המבצעת, או מחזיר null אם אין קבוצה מוגבלת.
query.limitToFirst
query.limitToLast
מספר
ריק
מאחזר את המגבלה על השאילתה המבצעת, או מחזיר null אם לא הוגדרה מגבלה.

מפעילים

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

יצירת תנאים

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

לקבלת הנחיות ליצירת כללים פשוטים ומוכנים לייצור, ראה כללי אבטחה בסיסיים .