شروط الكتابة لقواعد أمان Cloud Firestore

يستند هذا الدليل إلى دليل تنظيم قواعد الأمان. لعرض كيفية إضافة شروط إلى Cloud Firestore Security Rules. إذا لم تكن على دراية بأساسيات Cloud Firestore Security Rules، يمكنك الاطّلاع على دليل البدء .

الوحدة الأساسية لـ Cloud Firestore Security Rules هي الشرط. حاسمة الشرط هو تعبير منطقي يحدد ما إذا كانت عملية معينة السماح أو الرفض. يمكنك استخدام قواعد الأمان لكتابة الشروط التي فحص مصادقة المستخدم، والتحقق من صحة البيانات الواردة، أو حتى الوصول إلى أجزاء أخرى من قاعدة البيانات لديك.

المصادقة

أحد أنماط قواعد الأمان الأكثر شيوعًا هو التحكّم في الوصول استنادًا إلى حالة مصادقة المستخدم. على سبيل المثال، قد يريد تطبيقك السماح فقط المستخدمين الذين سجلوا الدخول لكتابة البيانات:

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 Security Rules بشكل ديناميكي بالوصول أو ترفض الوصول استنادًا إلى data المستند:

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 عمليات كتابة العمليات وأن قواعد الأمان تستخدم مكالمتَين للوصول إلى مستند من أجل والتحقق من صحة كل كتابة. في هذه الحالة، يستخدم كل إجراء كتابة طلبَي وصول من أصل 10، ويستخدم طلب الكتابة المجمّعة 6 من أصل 20 طلب وصول.

يؤدي تجاوز أي من هذين الحدّين إلى ظهور خطأ "تم رفض الإذن". قد يتم تخزين بعض طلبات الوصول إلى المستندات مؤقتًا، ولا يتم احتساب الطلبات المخزّنة مؤقتًا ضمن الحدود المسموح بها.

للحصول على شرح تفصيلي لكيفية تأثير هذه الحدود على المعاملات عمليات الكتابة المجمّعة، يمكنك الاطّلاع على دليل تأمين العمليات البسيطة.

الوصول إلى المكالمات والأسعار

يؤدي استخدام هذه الدوال إلى تنفيذ عملية قراءة في قاعدة بياناتك، ما يعني أنّه سيتم تحصيل رسوم منك مقابل قراءة المستندات حتى إذا رفضت قواعدك الطلب. يُرجى الاطّلاع على Cloud Firestore الأسعار لمزيد من المعلومات المحدّدة عن الفوترة.

الدوال المخصّصة

مع زيادة تعقيد قواعد الأمان، قد تحتاج إلى تضمين مجموعات من الشروط في دوال يمكنك إعادة استخدامها في مجموعة القواعد. قواعد الأمان تتيح الدوال المخصصة. يشبه أسلوب كتابة الدوالّ المخصّصة إلى حدٍّ ما أسلوب كتابة JavaScript، ولكنّ دوالّ قواعد الأمان مكتوبة بلغة خاصة بالمجال تفرض بعض القيود المهمة:

  • يمكن أن تحتوي الدوالّ على عبارة return واحدة فقط. لا يمكنهم تحتوي على أي منطق إضافي. على سبيل المثال، لا يمكنها تنفيذ حلقات أو الاتصال بخدمات خارجية.
  • يمكن للدوال الوصول تلقائيًا إلى الدوال والمتغيرات من النطاق التي يتم تعريفها فيها. على سبيل المثال، يمكن لدالة تم تعريفها ضمن نطاق service cloud.firestore الوصول إلى المتغيّر resource والدوالّ المضمّنة مثل get() وexists().
  • يمكن أن تستدعي الدوالّ دوالّ أخرى، ولكن لا يمكنها التكرار. إجمالي المكالمة يقتصر عمق تكديس الحزمة على 10.
  • في الإصدار v2 من القواعد، يمكن للدوالّ تحديد المتغيّرات باستخدام الكلمة الرئيسية let. يمكن أن تحتوي الدوالّ على ما يصل إلى 10 عمليات ربط let، ولكن يجب أن تنتهي بعبارة 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();
    }
  }
}

يؤدي استخدام الدوالّ في قواعد الأمان إلى تسهيل صيانتها مع زيادة تعقّد قواعدك.

القواعد ليست فلاتر

بعد تأمين بياناتك والبدء في كتابة طلبات بحث، تذكَّر أنّ قواعد security ليست فلاتر. لا يمكنك كتابة استعلام عن كافة المستندات الموجودة في البيانات التي نتوقع أن يعرض 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 كل طلب بحث استنادًا إلى نتيجة محتملة، وترفض الطلب إذا كان من المحتمل أن يعرض مستندًا ليس لبرنامج العميل إذن بقراءته. يجب أن تتبع طلبات البحث القيود التي تم ضبطها بواسطة قواعد الأمان الخاصة بك. لمزيد من المعلومات حول قواعد الأمان وطلبات البحث، راجع قسم والاستعلام عن البيانات.

الخطوات التالية