تعتمد هذه الصفحة على المفاهيم في هيكلة قواعد الأمان وشروط الكتابة لقواعد الأمان لشرح كيفية تفاعل قواعد أمان Cloud Firestore مع الاستعلامات. يلقي نظرة فاحصة على كيفية تأثير قواعد الأمان على الاستعلامات التي يمكنك كتابتها ويصف كيفية التأكد من أن استعلاماتك تستخدم نفس قيود قواعد الأمان الخاصة بك. توضح هذه الصفحة أيضًا كيفية كتابة قواعد الأمان للسماح بالاستعلامات أو رفضها بناءً على خصائص الاستعلام مثل 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
على UID للمستخدم الذي أنشأ المستند. تملأ مصادقة Firebase أيضًا متغير 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} / posts / {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} / posts / {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} / Transaction / {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
}
}
}
الخطوات التالية
- للحصول على مثال أكثر تفصيلاً للتحكم في الوصول المستند إلى الدور ، راجع تأمين الوصول إلى البيانات للمستخدمين والمجموعات .
- اقرأ مرجع قواعد الأمان .