تستند هذه الصفحة إلى المفاهيم الواردة في بناء قواعد الأمان وكتابة شروط قواعد الأمان لشرح كيفية استخدام Cloud Firestore Security Rules لإنشاء قواعد تسمح للعملاء بإجراء عمليات على بعض الحقول في مستند دون غيرها.
قد تكون هناك أوقات تريد فيها التحكم في التغييرات التي تطرأ على مستند ليس على مستوى المستند ولكن على مستوى الحقل.
على سبيل المثال، قد ترغب في السماح للعميل بإنشاء مستند أو تغييره، ولكن لا تسمح له بتحرير حقول معينة في هذا المستند. أو قد ترغب في فرض أن يحتوي أي مستند ينشئه العميل دائمًا على مجموعة معينة من الحقول. يتناول هذا الدليل كيفية تنفيذ بعض هذه المهام باستخدام Cloud Firestore Security Rules.
طلب إلى الذكاء الاصطناعي للحصول على مساعدة مستندة إليه
للحصول على مساعدة من الذكاء الاصطناعي، انسخ الطلب أدناه إلى وكيل الترميز بالذكاء الاصطناعي (مثل Gemini في "استوديو Android" وAntigravity وClaude Code وCodex وCursor). يمكنك تخصيص الطلب وتكراره مع الوكيل. انتقِل إلى مهارات وكلاء Firebase للحصول على معلومات مفصّلة عن التثبيت.
Help me use Firebase in my app.
1. Make sure that **Firebase agent skills** are installed and updated. For Claude Code, Codex, or Cursor agents, help me install the Firebase plugin. For other agents, run `npx skills add firebase/agent-skills`. Always try to use **Firebase agent skills** for Firebase-related tasks.
2. Help me write, validate, and deploy Firebase Security Rules to protect my app's Firestore data.
السماح بالوصول للقراءة فقط لحقول معيّنة
يتم تنفيذ عمليات القراءة في "القواعد" على مستوى المستند. إما أن تسترد المستند بالكامل، أو لا تسترد أي شيء. لا توجد طريقة لاسترداد مستند جزئي. من المستحيل استخدام قواعد الأمان وحدها لمنع المستخدمين من قراءة حقول معيّنة داخل مستند.
إذا كانت هناك حقول معيّنة في مستند تريد إخفاءها عن بعض المستخدمين، فإنّ أفضل طريقة هي وضعها في مستند منفصل. على سبيل المثال، يمكنك إنشاء مستند في مجموعة فرعية باسم private على النحو التالي:
/employees/{emp_id}
name: "Alice Hamilton",
department: 461,
start_date: <timestamp>
/employees/{emp_id}/private/finances
salary: 80000,
bonus_mult: 1.25,
perf_review: 4.2
بعد ذلك، يمكنك إضافة قواعد أمان لها مستويات مختلفة من الوصول إلى
المجموعتين. في هذا المثال، نستخدم مطالبات المصادقة المخصّصة
للإشارة إلى أنّه يمكن فقط للمستخدمين الذين لديهم مطالبة المصادقة المخصّصة role التي تساوي Finance
عرض المعلومات المالية للموظف.
service cloud.firestore {
match /databases/{database}/documents {
// Allow any logged in user to view the public employee data
match /employees/{emp_id} {
allow read: if request.resource.auth != null
// Allow only users with the custom auth claim of "Finance" to view
// the employee's financial data
match /private/finances {
allow read: if request.resource.auth &&
request.resource.auth.token.role == 'Finance'
}
}
}
}
تقييد الحقول عند إنشاء المستند
لا تتضمّن القواعد مخططات، ما يعني أنّه ما مِن قيود على مستوى قاعدة البيانات في ما يتعلّق بالحقول التي يتضمّنها المستند. على الرغم من أنّ هذه المرونة تسهّل عملية التطوير، قد تحتاج أحيانًا إلى التأكّد من أنّ العملاء يمكنهم فقط إنشاء مستندات تحتوي على حقول معيّنة أو لا تحتوي على حقول أخرى.
يمكنك إنشاء هذه القواعد من خلال فحص طريقة keys في الكائن
request.resource.data. هذه قائمة بجميع الحقول التي يحاول
العميل كتابتها في هذا المستند الجديد. من خلال دمج هذه المجموعة من الحقول مع دوال مثل hasOnly() أو hasAny()، يمكنك إضافة منطق يقيّد أنواع المستندات التي يمكن للمستخدم إضافتها إلى القواعد.
طلب حقول معيّنة في المستندات الجديدة
لنفترض أنّك أردت التأكّد من أنّ جميع المستندات التي تم إنشاؤها في مجموعة restaurant
تحتوي على حقل name وlocation وcity على الأقل. يمكنك إجراء ذلك من خلال استدعاء hasAll() في قائمة المفاتيح في المستند الجديد.
service cloud.firestore {
match /databases/{database}/documents {
// Allow the user to create a document only if that document contains a name
// location, and city field
match /restaurant/{restId} {
allow create: if request.resource.data.keys().hasAll(['name', 'location', 'city']);
}
}
}
يتيح ذلك إنشاء المطاعم بحقول أخرى أيضًا، ولكنه يضمن أن جميع المستندات التي أنشأها العميل تحتوي على هذه الحقول الثلاثة على الأقل.
حظر حقول معيّنة في المستندات الجديدة
وبالمثل، يمكنك منع العملاء من إنشاء مستندات تحتوي على حقول معيّنة باستخدام hasAny() مع قائمة بالحقول المحظورة. تكون نتيجة هذه الطريقة "صحيح" إذا كان المستند يحتوي على أي من هذه الحقول، لذا قد تحتاج إلى نفي النتيجة من أجل حظر حقول معيّنة.
على سبيل المثال، في المثال التالي، لا يُسمح للعملاء بإنشاء
مستند يحتوي على حقل average_score أو rating_count لأنّ هذه
الحقول ستتم إضافتها من خلال طلب من الخادم في وقت لاحق.
service cloud.firestore {
match /databases/{database}/documents {
// Allow the user to create a document only if that document does *not*
// contain an average_score or rating_count field.
match /restaurant/{restId} {
allow create: if (!request.resource.data.keys().hasAny(
['average_score', 'rating_count']));
}
}
}
إنشاء قائمة مسموح بها للحقول في المستندات الجديدة
بدلاً من حظر حقول معيّنة في المستندات الجديدة، يمكنك إنشاء قائمة بالحقول المسموح بها صراحةً في المستندات الجديدة. بعد ذلك،
يمكنك استخدام الدالة hasOnly()
للتأكّد من أنّ أي مستندات جديدة يتم إنشاؤها تحتوي على هذه الحقول فقط
(أو مجموعة فرعية من هذه الحقول) وليس غيرها.
service cloud.firestore {
match /databases/{database}/documents {
// Allow the user to create a document only if that document doesn't contain
// any fields besides the ones listed below.
match /restaurant/{restId} {
allow create: if (request.resource.data.keys().hasOnly(
['name', 'location', 'city', 'address', 'hours', 'cuisine']));
}
}
}
الجمع بين الحقول المطلوبة والاختيارية
يمكنك الجمع بين عمليتَي hasAll وhasOnly معًا في قواعد الأمان
لطلب بعض الحقول والسماح بحقول أخرى. على سبيل المثال، يتطلّب هذا المثال أن تحتوي جميع المستندات الجديدة على الحقول name وlocation وcity، ويسمح اختياريًا بالحقول address وhours وcuisine.
service cloud.firestore {
match /databases/{database}/documents {
// Allow the user to create a document only if that document has a name,
// location, and city field, and optionally address, hours, or cuisine field
match /restaurant/{restId} {
allow create: if (request.resource.data.keys().hasAll(['name', 'location', 'city'])) &&
(request.resource.data.keys().hasOnly(
['name', 'location', 'city', 'address', 'hours', 'cuisine']));
}
}
}
في سيناريو حقيقي، قد ترغب في نقل هذا المنطق إلى دالة مساعدة لتجنب تكرار التعليمات البرمجية الخاصة بك ولدمج الحقول الاختيارية والمطلوبة بسهولة أكبر في قائمة واحدة، مثل:
service cloud.firestore {
match /databases/{database}/documents {
function verifyFields(required, optional) {
let allAllowedFields = required.concat(optional);
return request.resource.data.keys().hasAll(required) &&
request.resource.data.keys().hasOnly(allAllowedFields);
}
match /restaurant/{restId} {
allow create: if verifyFields(['name', 'location', 'city'],
['address', 'hours', 'cuisine']);
}
}
}
تقييد الحقول عند التعديل
من الممارسات الأمنية الشائعة السماح للعملاء بتعديل بعض الحقول فقط دون غيرها. لا يمكنك تحقيق ذلك من خلال النظر فقط إلى قائمة request.resource.data.keys() الموضحة في القسم السابق، لأن هذه القائمة تمثل المستند الكامل كما سيبدو بعد التحديث، وبالتالي ستتضمن الحقول التي لم يغيرها العميل.
ومع ذلك، إذا كنت ستستخدم الدالة diff()، فيمكنك مقارنة request.resource.data مع الكائن resource.data، والذي يمثل المستند في قاعدة البيانات قبل التحديث. يؤدي ذلك إلى إنشاء عنصر mapDiff، وهو عنصر يحتوي على جميع التغييرات بين خريطتَين مختلفتَين.
By calling the affectedKeys()
method on this mapDiff, you can come up with a set of fields that were changed
in an edit. بعد ذلك، يمكنك استخدام دوال مثل
hasOnly()
أو hasAny()
للتأكّد من أنّ هذه المجموعة تحتوي (أو لا تحتوي) على عناصر معيّنة.
منع تغيير بعض الحقول
باستخدام طريقة hasAny() على المجموعة التي تم إنشاؤها بواسطة affectedKeys() ثم إلغاء النتيجة، يمكنك رفض أي طلب عميل يحاول تغيير الحقول التي لا تريد تغييرها.
على سبيل المثال، قد ترغب في السماح للعملاء بتحديث معلومات حول مطعم ولكن لا تغير متوسط درجاتهم أو عدد المراجعات.
service cloud.firestore {
match /databases/{database}/documents {
match /restaurant/{restId} {
// Allow the client to update a document only if that document doesn't
// change the average_score or rating_count fields
allow update: if (!request.resource.data.diff(resource.data).affectedKeys()
.hasAny(['average_score', 'rating_count']));
}
}
}
السماح بتغيير حقول معيّنة فقط
بدلاً من تحديد الحقول التي لا تريد تغييرها، يمكنك أيضًا استخدام الدالة
hasOnly()
لتحديد قائمة بالحقول التي تريد تغييرها. ويُعدّ هذا الإجراء أكثر أمانًا بشكل عام لأنّه لا يُسمح تلقائيًا بالكتابة في أي حقول مستندات جديدة إلى أن تسمح بذلك صراحةً في قواعد الأمان.
على سبيل المثال، بدلاً من حظر الحقلَين average_score وrating_count، يمكنك إنشاء قواعد أمان تسمح للعملاء بتغيير الحقول name وlocation وcity وaddress وhours وcuisine فقط.
service cloud.firestore {
match /databases/{database}/documents {
match /restaurant/{restId} {
// Allow a client to update only these 6 fields in a document
allow update: if (request.resource.data.diff(resource.data).affectedKeys()
.hasOnly(['name', 'location', 'city', 'address', 'hours', 'cuisine']));
}
}
}
يعني ذلك أنّه إذا كانت مستندات المطاعم في بعض الإصدارات المستقبلية من تطبيقك
تتضمّن حقل telephone، ستفشل محاولات تعديل هذا الحقل
إلى أن ترجع وتضيف هذا الحقل إلى قائمة hasOnly() في قواعد
الأمان.
فرض أنواع الحقول
من التأثيرات الأخرى لعدم استخدام القواعد للمخططات هو عدم فرض أي قيود على مستوى قاعدة البيانات على أنواع البيانات التي يمكن تخزينها في حقول معيّنة. يمكنك فرض ذلك في قواعد الأمان باستخدام عامل التشغيل is.
على سبيل المثال، تفرض قاعدة الأمان التالية أن يكون حقل score للمراجعة عددًا صحيحًا، وأن تكون حقول headline وcontent وauthor_name سلاسل، وأن يكون review_date طابعًا زمنيًا.
service cloud.firestore {
match /databases/{database}/documents {
match /restaurant/{restId} {
// Restaurant rules go here...
match /review/{reviewId} {
allow create: if (request.resource.data.score is int &&
request.resource.data.headline is string &&
request.resource.data.content is string &&
request.resource.data.author_name is string &&
request.resource.data.review_date is timestamp
);
}
}
}
}
أنواع البيانات الصالحة لعامل التشغيل is هي bool وbytes وfloat وint وlist وlatlng وnumber وpath وmap وstring وtimestamp. يتيح عامل التشغيل is أيضًا أنواع البيانات constraint وduration وset وmap_diff، ولكن بما أنّها يتم إنشاؤها من خلال لغة قواعد الأمان نفسها وليس من خلال العملاء، نادرًا ما يتم استخدامها في معظم التطبيقات العملية.
لا يتيح نوعا البيانات list وmap استخدام الأنواع العامة أو وسيطات الأنواع.
بعبارة أخرى، يمكنك استخدام قواعد الأمان لفرض احتواء حقل معيّن على قائمة أو خريطة، ولكن لا يمكنك فرض احتواء حقل على قائمة بجميع الأعداد الصحيحة أو جميع السلاسل.
وبالمثل، يمكنك استخدام قواعد الأمان لفرض قيم الأنواع لإدخالات محددة في قائمة أو خريطة (باستخدام تدوين الأقواس أو أسماء المفاتيح على التوالي)، ولكن لا يوجد اختصار لفرض أنواع البيانات لجميع الأعضاء في خريطة أو قائمة في وقت واحد.
على سبيل المثال، تضمن القواعد التالية أن يحتوي حقل tags في مستند على قائمة وأن يكون الإدخال الأول عبارة عن سلسلة. ويضمن أيضًا أنّ
الحقل product يحتوي على خريطة تحتوي بدورها على اسم منتج
يكون عبارة عن سلسلة وكمية تكون عبارة عن عدد صحيح.
service cloud.firestore {
match /databases/{database}/documents {
match /orders/{orderId} {
allow create: if request.resource.data.tags is list &&
request.resource.data.tags[0] is string &&
request.resource.data.product is map &&
request.resource.data.product.name is string &&
request.resource.data.product.quantity is int
}
}
}
}
يجب فرض أنواع الحقول عند إنشاء مستند وتعديله. لذلك، قد تحتاج إلى إنشاء دالة مساعِدة يمكنك استدعاؤها في كل من قسمَي الإنشاء والتعديل في قواعد الأمان.
service cloud.firestore {
match /databases/{database}/documents {
function reviewFieldsAreValidTypes(docData) {
return docData.score is int &&
docData.headline is string &&
docData.content is string &&
docData.author_name is string &&
docData.review_date is timestamp;
}
match /restaurant/{restId} {
// Restaurant rules go here...
match /review/{reviewId} {
allow create: if reviewFieldsAreValidTypes(request.resource.data) &&
// Other rules may go here
allow update: if reviewFieldsAreValidTypes(request.resource.data) &&
// Other rules may go here
}
}
}
}
فرض الأنواع للحقول الاختيارية
من المهم تذكُّر أنّ استدعاء request.resource.data.foo في مستند لا يتضمّن foo يؤدي إلى حدوث خطأ، وبالتالي فإنّ أي قاعدة أمان تُجري هذا الاستدعاء سترفض الطلب. يمكنك معالجة هذه الحالة باستخدام طريقة get في request.resource.data. تتيح لك طريقة get تقديم وسيطة تلقائية للحقل الذي تسترجعه من خريطة إذا لم يكن هذا الحقل موجودًا.
على سبيل المثال، إذا كانت مستندات المراجعة تحتوي أيضًا على حقل photo_url اختياري
وحقل tags اختياري تريد التحقّق من أنّهما سلاسل وقوائم
على التوالي، يمكنك تحقيق ذلك من خلال إعادة كتابة
دالة reviewFieldsAreValidTypes على النحو التالي:
function reviewFieldsAreValidTypes(docData) {
return docData.score is int &&
docData.headline is string &&
docData.content is string &&
docData.author_name is string &&
docData.review_date is timestamp &&
docData.get('photo_url', '') is string &&
docData.get('tags', []) is list;
}
يؤدي ذلك إلى رفض المستندات التي تحتوي على tags، ولكنها ليست قائمة، مع السماح بالمستندات التي لا تحتوي على حقل tags (أو photo_url).
لا يُسمح مطلقًا بعمليات الكتابة الجزئية
ملاحظة أخيرة حول Cloud Firestore Security Rules هي أنّها إما تسمح للعميل بإجراء تغيير على مستند أو ترفض التعديل بأكمله. لا يمكنك إنشاء قواعد أمان تقبل عمليات الكتابة في بعض الحقول في المستند مع رفض حقول أخرى في العملية نفسها.