Catch up on highlights from Firebase at Google I/O 2023. Learn more

شروط الكتابة لقواعد أمان 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 من 10 مكالمات وصول ويستخدم طلب الكتابة المجمّع 6 من أصل 20 مكالمة وصول.

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

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

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

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

وظائف مخصصة

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

  • يمكن أن تحتوي الوظائف على عبارة return واحدة فقط. لا يمكن أن تحتوي على أي منطق إضافي. على سبيل المثال ، لا يمكنهم تنفيذ حلقات أو استدعاء خدمات خارجية.
  • يمكن للوظائف الوصول تلقائيًا إلى الوظائف والمتغيرات من النطاق الذي تم تعريفها فيه. على سبيل المثال ، دالة محددة في نطاق service cloud.firestore لها حق الوصول إلى متغير resource والوظائف المضمنة مثل get() و exists() .
  • قد تستدعي الوظائف وظائف أخرى ولكنها قد لا تتكرر. إجمالي عمق مكدس الاستدعاء محدد بـ 10.
  • في الإصدار v2 من القواعد ، يمكن للوظائف تحديد المتغيرات باستخدام الكلمة الرئيسية let . يمكن أن تحتوي الوظائف على ما يصل إلى 10 روابط let ، ولكن يجب أن تنتهي ببيان عودة.

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

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