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

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

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

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

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

وظائف مخصصة

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

  • يمكن أن تحتوي الوظائف على عبارة 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();
    }
  }
}

إن استخدام الوظائف في قواعد الأمان الخاصة بك يجعلها أكثر قابلية للصيانة مع تزايد تعقيد قواعدك.

القواعد ليست مرشحات

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

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