تعتمد هذه الصفحة على المفاهيم في
هيكلة قواعد الأمان
شروط الكتابة لقواعد الأمان لتوضيح كيفية
تفاعل "Cloud Firestore Security Rules" مع طلبات البحث يلقي نظرة فاحصة على كيفية
على الاستعلامات التي يمكنك كتابتها وتصف كيفية ضمان
تستخدم الطلبات نفس القيود مثل قواعد الأمان. هذه الصفحة أيضًا
وصف كيفية كتابة قواعد الأمان للسماح أو رفض الاستعلامات بناءً على الاستعلام
المواقع مثل limit
وorderBy
.
القواعد ليست فلاتر
عند كتابة الاستعلامات لاسترداد المستندات، ضع في اعتبارك أن قواعد الأمان هي وليس عوامل تصفية - الاستعلامات هي كلها أو لا شيء منها. لتوفير الوقت والموارد، يقيّم Cloud Firestore طلب بحث مقارنةً بمجموعة النتائج المحتمَلة الخاصة به. بدلاً من القيم الفعلية لجميع مستنداتك. إذا كان بإمكان الاستعلام مستندات لا يمتلك العميل إذنًا بقراءتها، أو فشل الطلب بأكمله.
الطلبات وقواعد الأمان
كما توضح الأمثلة أدناه، يجب عليك كتابة استعلاماتك لتناسب قيود قواعد الأمان لديك.
تأمين المستندات وطلب البحث استنادًا إلى auth.uid
يوضح المثال التالي كيفية كتابة استعلام لاسترداد المستندات
محمي بواسطة قاعدة أمان. ضع في اعتبارك قاعدة بيانات تحتوي على مجموعة من
مستندان (story
):
/stories/{storyid}
{
title: "A Great Story",
content: "Once upon a time...",
author: "some_auth_id",
published: false
}
بالإضافة إلى الحقلين title
وcontent
، يخزِّن كل مستند
الحقلان author
وpublished
لاستخدامهما للتحكم في الوصول. تفترض هذه الأمثلة
يستخدم التطبيق مصادقة Firebase لضبط حقل author
إلى المعرف الفريد للمستخدم الذي أنشأ المستند. الإعداد عن بُعد
تملأ المصادقة أيضًا المتغيّر request.auth
في
بقواعد الأمان.
تستخدم قاعدة الأمان التالية request.auth
متغيّرات resource.data
لتقييد إمكانية الوصول للقراءة والكتابة لكل متغيّر
story
إلى المؤلف:
service cloud.firestore {
match /databases/{database}/documents {
match /stories/{storyid} {
// Only the authenticated user who authored the document can read or write
allow read, write: if request.auth != null && request.auth.uid == resource.data.author;
}
}
}
لنفرض أنّ تطبيقك يتضمّن صفحة تعرض للمستخدم قائمة تضم story
.
الوثائق التي ألّفوها. يمكنك استخدام ما يلي:
لملء هذه الصفحة. ومع ذلك، سيفشل هذا الاستعلام، لأنه لا
تتضمن القيود نفسها مثل قواعد الأمان:
غير صالح: قيود طلب البحث غير متطابقة قيود قواعد الأمان
// This query will fail
db.collection("stories").get()
يتعذّر تنفيذ طلب البحث حتى إذا كان المستخدم الحالي هو مؤلف كل
مستند واحد (story
) وسبب هذا السلوك هو أنه عندما
يطبِّق Cloud Firestore قواعد الأمان، ويقيّم طلب البحث.
مقارنةً بمجموعة النتائج المحتملة، وليس على الخصائص الفعلية
مستندات في قاعدة البيانات لديك. إذا كان من المحتمل أن يتضمّن طلب البحث مستندات
التي تنتهك قواعد الأمان لديك، فسيفشل الاستعلام.
في المقابل، ينجح الاستعلام التالي، لأنه يتضمن نفس
في الحقل author
باعتبارها قواعد الأمان:
صالح: تطابق قيود طلب البحث مع الأمان قيود القواعد
var user = firebase.auth().currentUser;
db.collection("stories").where("author", "==", user.uid).get()
تأمين المستندات وطلب البحث عنها استنادًا إلى حقل
ولتوضيح التفاعل بين الاستعلامات والقواعد بشكل أكبر، يمكن
تقوم القواعد أدناه بتوسيع إمكانية الوصول للقراءة لمجموعة stories
للسماح لأي مستخدم
قراءة story
مستندات حيث تم ضبط الحقل published
على true
.
service cloud.firestore {
match /databases/{database}/documents {
match /stories/{storyid} {
// Anyone can read a published story; only story authors can read unpublished stories
allow read: if resource.data.published == true || (request.auth != null && request.auth.uid == resource.data.author);
// Only story authors can write
allow write: if request.auth != null && request.auth.uid == resource.data.author;
}
}
}
يجب أن يتضمن طلب الصفحات المنشورة نفس القيود المفروضة على الأمان القواعد:
db.collection("stories").where("published", "==", true).get()
يضمن قيد الاستعلام .where("published", "==", true)
أن
تكون قيمة resource.data.published
هي true
لأي نتيجة. لذلك، لا يعتقد هذا الاستعلام
يستوفي قواعد الأمان ويُسمح له بقراءة البيانات.
OR
طلب بحث
عند تقييم طلب بحث OR
منطقي (or
أو in
أو array-contains-any
)
استنادًا إلى مجموعة قواعد، يقيّم "Cloud Firestore" كل قيمة مقارنة.
على حدة. يجب أن تستوفي كل قيمة مقارنة قيود قاعدة الأمان. بالنسبة
على سبيل المثال، بالنسبة إلى
القاعدة التالية:
match /mydocuments/{doc} {
allow read: if resource.data.x > 5;
}
غير صالح: لا يضمن طلب البحث أن
x > 5
لكل المستندات المحتملة
// These queries will fail
query(db.collection("mydocuments"),
or(where("x", "==", 1),
where("x", "==", 6)
)
)
query(db.collection("mydocuments"),
where("x", "in", [1, 3, 6, 42, 99])
)
صالحة: يضمن طلب البحث أن
x > 5
لكل المستندات المحتملة
query(db.collection("mydocuments"),
or(where("x", "==", 6),
where("x", "==", 42)
)
)
query(db.collection("mydocuments"),
where("x", "in", [6, 42, 99, 105, 200])
)
تقييم القيود على الاستعلامات
يمكن لقواعد الأمان أيضًا قبول الطلبات أو رفضها وفقًا لقيودها.
يحتوي المتغيّر request.query
على limit
وoffset
وorderBy
من خصائص طلب البحث. على سبيل المثال، قواعد الأمان
يمكنه رفض أي استعلام لا يضع حدًا أقصى لعدد المستندات
استردادها إلى نطاق معين:
allow list: if request.query.limit <= 10;
توضح مجموعة القواعد التالية كيفية كتابة قواعد أمان تعمل على تقييم
القيود المفروضة على الاستعلامات. يؤدي هذا المثال إلى توسيع نطاق stories
السابق.
مع التغييرات التالية:
- تفصل مجموعة القواعد قاعدة القراءة إلى قواعد لـ
get
وlist
. - تحصر قاعدة
get
استرداد مستندات فردية بالمستندات العلنية أو المستندات التي ألّفها المستخدم. - تطبّق القاعدة
list
القيود نفسها التي يتم تطبيقها علىget
ولكن على طلبات البحث. أُنشأها جون هنتر، الذي كان متخصصًا أيضًا من حد طلبات البحث، ثم يرفض أي استعلام بدون حد أو باستخدام الحد الأقصى أكبر من 10. - تحدِّد مجموعة القواعد دالة
authorOrPublished()
لتجنُّب استخدام الرموز البرمجية. التكرار.
service cloud.firestore {
match /databases/{database}/documents {
match /stories/{storyid} {
// Returns `true` if the requested story is 'published'
// or the user authored the story
function authorOrPublished() {
return resource.data.published == true || request.auth.uid == resource.data.author;
}
// Deny any query not limited to 10 or fewer documents
// Anyone can query published stories
// Authors can query their unpublished stories
allow list: if request.query.limit <= 10 &&
authorOrPublished();
// Anyone can retrieve a published story
// Only a story's author can retrieve an unpublished story
allow get: if authorOrPublished();
// Only a story's author can write to a story
allow write: if request.auth.uid == resource.data.author;
}
}
}
طلبات بحث مجموعة المختارات وقواعد الأمان
تقتصر طلبات البحث تلقائيًا على مجموعة واحدة ويتم استرداد النتائج فيها. من هذه المجموعة فقط. مع مجموعات طلبات البحث، يمكنك استرداد النتائج من مجموعة مجموعات تتكون من جميع المجموعات مع نفس المعرّف. يصف هذا القسم كيفية تأمين طلبات بحث مجموعة المجموعات. باستخدام قواعد الأمان.
تأمين المستندات وطلب البحث عنها استنادًا إلى مجموعات المجموعات
في قواعد الأمان لديك، يجب أن تسمح استعلامات مجموعة المجموعات عن طريق كتابة قاعدة لمجموعة المجموعات:
- تأكد من أن
rules_version = '2';
هو السطر الأول من مجموعة القواعد. فيديو مقالات استعلامات المجموعة تتطلب سلوك أمان حرف البدل المتكرر المتكرر{name=**}
من القواعد 2. - كتابة قاعدة لمجموعة المجموعات باستخدام
match /{path=**}/[COLLECTION_ID]/{doc}
على سبيل المثال، لنفترض أن هناك منتدى منظمًا إلى forum
مستندات تحتوي على
posts
مجموعة فرعية:
/منتديات/{forumid}/post/{postid}
{
author: "some_auth_id",
authorname: "some_username",
content: "I just read a great story.",
}
في هذا التطبيق، نجعل المشاركات قابلة للتعديل من خلال مالكيها ويمكن قراءتها بواسطة المستخدمون الذين تمت مصادقتهم:
service cloud.firestore {
match /databases/{database}/documents {
match /forums/{forumid}/posts/{post} {
// Only authenticated users can read
allow read: if request.auth != null;
// Only the post author can write
allow write: if request.auth != null && request.auth.uid == resource.data.author;
}
}
}
ويمكن لأي مستخدم تمت مصادقته استرداد مشاركات أي منتدى فردي:
db.collection("forums/technology/posts").get()
ولكن ماذا لو كنت تريد عرض مشاركاته للمستخدم الحالي عبر جميع المنتديات؟
يمكنك استخدام طلب بحث عن مجموعة مجموعات لاسترداد
نتائج من كل المجموعات البالغ عددها posts
:
var user = firebase.auth().currentUser;
db.collectionGroup("posts").where("author", "==", user.uid).get()
في قواعد الأمان، يجب السماح بهذا الطلب عن طريق
كتابة قاعدة قراءة أو قائمة لمجموعة المجموعات posts
:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// Authenticated users can query the posts collection group
// Applies to collection queries, collection group queries, and
// single document retrievals
match /{path=**}/posts/{post} {
allow read: if request.auth != null;
}
match /forums/{forumid}/posts/{postid} {
// Only a post's author can write to a post
allow write: if request.auth != null && request.auth.uid == resource.data.author;
}
}
}
يُرجى العِلم أنّ هذه القواعد ستنطبق على جميع المجموعات التي تحمل المعرّف posts
.
بغض النظر عن التسلسل الهرمي. على سبيل المثال، تسري هذه القواعد على جميع ما يلي:
posts
مجموعة:
/posts/{postid}
/forums/{forumid}/posts/{postid}
/forums/{forumid}/subforum/{subforumid}/posts/{postid}
طلبات بحث مجموعة مجموعات آمنة استنادًا إلى حقل
مثل طلبات البحث في مجموعة واحدة، يجب أن تتوافق طلبات بحث مجموعة المجموعات أيضًا مع
القيود التي تفرضها قواعد الأمان لديك. على سبيل المثال، يمكننا إضافة published
إلى كل مشاركة في المنتدى كما فعلنا في مثال stories
أعلاه:
/منتديات/{forumid}/post/{postid}
{
author: "some_auth_id",
authorname: "some_username",
content: "I just read a great story.",
published: false
}
ويمكننا بعد ذلك كتابة قواعد لمجموعة المجموعات posts
استنادًا إلى
حالة published
والمشاركة author
:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// Returns `true` if the requested post is 'published'
// or the user authored the post
function authorOrPublished() {
return resource.data.published == true || request.auth.uid == resource.data.author;
}
match /{path=**}/posts/{post} {
// Anyone can query published posts
// Authors can query their unpublished posts
allow list: if authorOrPublished();
// Anyone can retrieve a published post
// Authors can retrieve an unpublished post
allow get: if authorOrPublished();
}
match /forums/{forumid}/posts/{postid} {
// Only a post's author can write to a post
allow write: if request.auth.uid == resource.data.author;
}
}
}
باستخدام هذه القواعد، يمكن لعملاء الويب وApple وAndroid إجراء طلبات البحث التالية:
يمكن لأي مستخدم استرداد المشاركات المنشورة في منتدى:
db.collection("forums/technology/posts").where('published', '==', true).get()
يمكن لأي مستخدم استرداد مشاركات المؤلف المنشورة في جميع المنتديات:
db.collectionGroup("posts").where("author", "==", "some_auth_id").where('published', '==', true).get()
ويمكن للمؤلفين استرداد جميع مشاركاتهم المنشورة وغير المنشورة على جميع المنتديات:
var user = firebase.auth().currentUser; db.collectionGroup("posts").where("author", "==", user.uid).get()
تأمين المستندات وطلب البحث عنها استنادًا إلى مجموعة المجموعات ومسار المستند
وفي بعض الحالات، قد ترغب في تقييد طلبات بحث مجموعة المجموعات استنادًا إلى مسار المستند. لإنشاء هذه القيود، يمكنك استخدام الأساليب نفسها تأمين المستندات والاستعلام عنها بناءً على أحد الحقول.
ضع في اعتبارك تطبيقًا يتتبع معاملات كل مستخدم من بين العديد من خدمات صرف الأوراق المالية والعملات المشفّرة:
/users/{userid}/Exchange/{Exchangeid}/transactions/{transaction}
{
amount: 100,
exchange: 'some_exchange_name',
timestamp: April 1, 2019 at 12:00:00 PM UTC-7,
user: "some_auth_id",
}
لاحِظ الحقل user
. نحن نعرف المستخدم الذي يمتلك transaction
من مسار المستند، نكرر هذه المعلومات في كل
مستند transaction
لأنه يتيح لنا القيام بأمرين:
كتابة استعلامات عن مجموعة المجموعات مقصورة على المستندات التي تشتمل على
/users/{userid}
محدد في مسار المستند. على سبيل المثال:var user = firebase.auth().currentUser; // Return current user's last five transactions across all exchanges db.collectionGroup("transactions").where("user", "==", user).orderBy('timestamp').limit(5)
فرض هذا التقييد على جميع طلبات البحث في مجموعة
transactions
بحيث لا يمكن لمستخدم واحد استرداد مستنداتtransaction
لمستخدم آخر.
ونفرض هذا القيد في قواعد الأمان ونضمِّن ميزة التحقّق من صحة البيانات.
للحقل user
:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{path=**}/transactions/{transaction} {
// Authenticated users can retrieve only their own transactions
allow read: if resource.data.user == request.auth.uid;
}
match /users/{userid}/exchange/{exchangeid}/transactions/{transaction} {
// Authenticated users can write to their own transactions subcollections
// Writes must populate the user field with the correct auth id
allow write: if userid == request.auth.uid && request.data.user == request.auth.uid
}
}
}
الخطوات التالية
- للحصول على مثال أكثر تفصيلاً للتحكم في الوصول استنادًا إلى الدور، راجع تأمين البيانات إذن الوصول للمستخدمين والمجموعات:
- اطّلِع على مرجع قواعد الأمان.