يستنِد هذا الدليل إلى التعرّف على البنية الأساسية لدليل لغة Firebase Security Rules لتوضيح كيفية إضافة شروط إلى Firebase Security Rules لـ Cloud Storage.
الوحدة الأساسية للعنصر Cloud Storage Security Rules هي الشرط. العبارة
الشرطية هي تعبير منطقي يحدّد ما إذا كان يجب السماح بإجراء معيّن
أو رفضه. بالنسبة إلى القواعد الأساسية، يعمل استخدام القيم الثابتة true
وfalse
كشرط بشكل جيد جدًا. ولكنّ لغة Firebase Security Rules for Cloud Storage
تمنحك طرقًا لكتابة شروط أكثر تعقيدًا يمكنها:
- التحقّق من مصادقة المستخدم
- التحقق من صحة البيانات الواردة
المصادقة
Firebase Security Rules لنظام التشغيل Cloud Storage يدمج مع Firebase Authentication لتوفير مصادقة قوية تستند إلى المستخدمين في Cloud Storage. يتيح ذلك التحكّم الدقيق في الوصول استنادًا إلى مطالبات رمز Firebase Authentication المميّز.
عندما ينفّذ مستخدم تمت مصادقته طلبًا مقابل Cloud Storage،
تتم تعبئة المتغير request.auth
بـ uid
(request.auth.uid
) الخاص بالمستخدم، وكذلك مطالبات Firebase Authentication JWT
(request.auth.token
).
بالإضافة إلى ذلك، عند استخدام المصادقة المخصّصة، يتم عرض مطالبات إضافية
في الحقل request.auth.token
.
عندما يُجري مستخدم لم يتم مصادقة هويته طلبًا، يكون المتغيّر request.auth
هو
null
.
باستخدام هذه البيانات، هناك عدة طرق شائعة لاستخدام المصادقة لتأمين الملفات:
- علني: تجاهل
request.auth
- خاص ومصادق عليه: تأكَّد من أنّ
request.auth
ليسnull
- خاص بالمستخدم: تأكَّد من أنّ
request.auth.uid
يساوي مسارًاuid
- المجموعة الخاصة: تحقَّق من مطالبات الرمز المميّز المخصّص لمطابقة مطالبة مختارة، أو اقرأ البيانات الوصفية للملف لمعرفة ما إذا كان هناك حقل للبيانات الوصفية
علني
يمكن اعتبار أي قاعدة لا تأخذ سياق request.auth
في الاعتبار قاعدة
public
، لأنّها لا تأخذ سياق مصادقة المستخدم في الاعتبار.
يمكن أن تكون هذه القواعد مفيدة لعرض البيانات المتاحة للجميع، مثل مواد عرض الألعاب أو الملفات
الصوتية أو المحتوى الثابت الآخر.
// Anyone to read a public image if the file is less than 100kB // Anyone can upload a public file ending in '.txt' match /public/{imageId} { allow read: if resource.size < 100 * 1024; allow write: if imageId.matches(".*\\.txt"); }
محتوى خاص تمّت مصادقته
في بعض الحالات، قد تحتاج إلى أن تكون البيانات مرئية لجميع المستخدمين الذين تم مصادقة هويتهم في
تطبيقك، ولكن ليس للمستخدمين الذين لم يتم مصادقة هويتهم. بما أنّ المتغيّر request.auth
يكون null
لجميع المستخدمين الذين لم تتم مصادقة هويتهم، ما عليك سوى التحقّق مما إذا كان المتغيّر request.auth
موجودًا لطلب المصادقة:
// Require authentication on all internal image reads match /internal/{imageId} { allow read: if request.auth != null; }
معلومات خاصة بالمستخدم
إنّ الحالة الأكثر شيوعًا لاستخدام request.auth
هي منح مستخدمين individual
أذونات دقيقة على ملفاتهم، بدءًا من تحميل صور الملف الشخصي
ووصولاً إلى قراءة المستندات الخاصة.
بما أنّ الملفات في Cloud Storage تتضمّن "مسارًا" كاملاً إلى الملف، كل ما يتطلبه الأمر لإنشاء ملف يتحكّم فيه المستخدم هو إضافة معلومات فريدة تحدّد هوية المستخدم في بادئة اسم الملف (مثل uid
للمستخدم) ويمكن التحقّق منها عند تقييم القاعدة:
// Only a user can upload their profile picture, but anyone can view it match /users/{userId}/profilePicture.png { allow read; allow write: if request.auth.uid == userId; }
المجموعة خاصة
ومن حالات الاستخدام الشائعة الأخرى السماح بأذونات المجموعة على عنصر، مثل السماح لعدة أعضاء في الفريق بالتعاون في مستند مشترَك. هناك عدة طرق لإجراء ذلك:
- يمكنك إنشاء رمز مميّز مخصص لـ Firebase Authentication يتضمن معلومات إضافية حول أحد أعضاء المجموعة (مثل رقم تعريف المجموعة)
- يجب تضمين معلومات المجموعة (مثل رقم تعريف المجموعة أو قائمة
uid
المعتمَدين) في البيانات الوصفية للملف.
بمجرد تخزين هذه البيانات في الرمز المميز أو بيانات التعريف للملف، يمكن الرجوع إليها من داخل قاعدة:
// Allow reads if the group ID in your token matches the file metadata's `owner` property // Allow writes if the group ID is in the user's custom token match /files/{groupId}/{fileName} { allow read: if resource.metadata.owner == request.auth.token.groupId; allow write: if request.auth.token.groupId == groupId; }
طلب التقييم
يتم تقييم عمليات التحميل وعمليات التنزيل وتغييرات البيانات الوصفية وعمليات الحذف باستخدام
request
المرسل إلى Cloud Storage. بالإضافة إلى المعرّف الفريد للمستخدم
وحمولة Firebase Authentication في عنصر request.auth
كما هو موضّح أعلاه، يحتوي المتغيّر request
على مسار الملف الذي يتم تنفيذ الطلب فيه
والوقت الذي تم فيه استلام الطلب وقيمة resource
الجديدة
إذا كان الطلب عبارة عن عملية كتابة.
يحتوي عنصر request
أيضًا على المعرّف الفريد للمستخدم وحمله
Firebase Authentication في عنصر request.auth
، وسيتم شرحه
بمزيد من التفصيل في قسم الأمان المستنِد إلى المستخدم
في المستندات.
في ما يلي قائمة كاملة بالسمات في عنصر request
:
الموقع | النوع | الوصف |
---|---|---|
auth |
map<string, string> | عندما يكون المستخدم مسجِّلاً الدخول، يقدّم uid ، وهو المعرّف الفريد للمستخدم،
token ، وهو خريطة لمطالبات Firebase Authentication JWT. بخلاف ذلك، سيكون
null . |
params |
خريطة <string, string> | خريطة تحتوي على مَعلمات طلب البحث |
path |
المسار | path يمثّل المسار الذي يتم تنفيذ الطلب عليه
|
resource |
map<string, string> | قيمة المورد الجديدة، لا تظهر إلا في طلبات write .
|
time |
الطابع الزمني | طابع زمني يمثّل وقت الخادم الذي يتم تقييم الطلب فيه |
تقييم الموارد
عند تقييم القواعد، قد تحتاج أيضًا إلى تقييم البيانات الوصفية للملف الذي يتم تحميله أو تنزيله أو تعديله أو حذفه. يتيح لك ذلك إنشاء قواعد معقدة وفعّالة تؤدي إلى تنفيذ إجراءات، مثل السماح فقط بتحميل ملفات ذات أنواع محتوى معيّنة، أو حذف الملفات التي تزيد مساحتها عن حجم معيّن فقط.
Firebase Security Rules لـ Cloud Storage: يوفّر البيانات الوصفية للملف في resource
كائن، الذي يحتوي على أزواج مفتاح/قيمة للبيانات الوصفية التي تظهر في
Cloud Storage كائن. يمكن فحص هذه المواقع في طلبات read
أو
write
لضمان سلامة البيانات.
في طلبات write
(مثل عمليات التحميل وتعديل البيانات الوصفية وعمليات الحذف)، بالإضافة إلى عنصر resource
الذي يحتوي على البيانات الوصفية للملف الذي
يوجد حاليًا في مسار الطلب، يمكنك أيضًا استخدام request.resource
الذي يحتوي على مجموعة فرعية من البيانات الوصفية للملف التي سيتم
كتابتها إذا كان الإذن بالكتابة مسموحًا به. يمكنك استخدام هاتين القيمتين لضمان سلامة البيانات
أو فرض قيود على التطبيق مثل نوع الملف أو حجمه.
في ما يلي قائمة كاملة بالسمات في عنصر resource
:
الموقع | النوع | الوصف |
---|---|---|
name |
السلسلة | الاسم الكامل للعنصر |
bucket |
السلسلة | اسم الحزمة التي يقع فيها هذا العنصر |
generation |
int | إنشاء عنصر Google Cloud Storage لهذا العنصر. |
metageneration |
int | Google Cloud Storage الجيل التعريفي للكائن لهذا الكائن. |
size |
int | حجم العنصر بالبايت |
timeCreated |
الطابع الزمني | طابع زمني يمثّل وقت إنشاء عنصر |
updated |
الطابع الزمني | طابع زمني يمثّل وقت آخر تعديل لعنصر |
md5Hash |
السلسلة | تجزئة MD5 للعنصر |
crc32c |
السلسلة | تجزئة crc32c للعنصر |
etag |
السلسلة | علامة etag المرتبطة بهذا العنصر |
contentDisposition |
السلسلة | ترتيب المحتوى المرتبط بهذا العنصر |
contentEncoding |
السلسلة | ترميز المحتوى المرتبط بهذا العنصر |
contentLanguage |
السلسلة | لغة المحتوى المرتبطة بهذا العنصر. |
contentType |
السلسلة | نوع المحتوى المرتبط بهذا العنصر |
metadata |
خريطة <string, string> | أزواج مفتاح/قيمة للبيانات الوصفية المخصّصة الإضافية التي يحدّدها المطوّر |
يحتوي request.resource
على كل هذه القيم باستثناء generation
،
metageneration
، etag
، timeCreated
، وupdated
.
التحسين باستخدام Cloud Firestore
يمكنك الوصول إلى المستندات في Cloud Firestore لتقييم معايير التفويض الأخرى.
باستخدام الدالتَين firestore.get()
وfirestore.exists()
، يمكن لقواعد
الأمان تقييم الطلبات الواردة مقارنةً بالمستندات في Cloud Firestore.
تتوقع الدالتان firestore.get()
وfirestore.exists()
مسارات محددة بالكامل للمستندات. عند استخدام المتغيّرات لإنشاء مسارات لسمتي
firestore.get()
وfirestore.exists()
، عليك إزالة ترميز
المتغيّرات بشكل صريح باستخدام بنية $(variable)
.
في المثال أدناه، نلاحظ قاعدة تحصر إمكانية الوصول للقراءة إلى الملفات على المستخدمين الأعضاء في أندية معيَّنة.
service firebase.storage { match /b/{bucket}/o { match /users/{club}/files/{fileId} { allow read: if club in firestore.get(/databases/(default)/documents/users/$(request.auth.id)).memberships } } }
service firebase.storage { match /b/{bucket}/o { match /users/{userId}/photos/{fileId} { allow read: if firestore.exists(/databases/(default)/documents/users/$(userId)/friends/$(request.auth.id)) } } }
بعد إنشاء وحفظ أول Cloud Storage Security Rules يستخدِم وظائف Cloud Firestore هذه، سيُطلب منك في وحدة تحكّم Firebase أو واجهة سطر الأوامر Firebase تفعيل الأذونات لربط المنتجَين.
يمكنك إيقاف الميزة من خلال إزالة دور في "إدارة الهوية وإمكانية الوصول"، كما هو موضّح في مقالة إدارة ونشر Firebase Security Rules.
التحقّق من صحة البيانات
يمكن أيضًا استخدام Firebase Security Rules لـ Cloud Storage للتحقّق من صحة البيانات، بما في ذلك
التحقّق من اسم الملف ومساره بالإضافة إلى سمات البيانات الوصفية للملف، مثل
contentType
وsize
.
service firebase.storage { match /b/{bucket}/o { match /images/{imageId} { // Only allow uploads of any image file that's less than 5MB allow write: if request.resource.size < 5 * 1024 * 1024 && request.resource.contentType.matches('image/.*'); } } }
الدوال المخصّصة
مع زيادة تعقيد Firebase Security Rules، قد تحتاج إلى تضمين مجموعات من الشروط في دوال يمكنك إعادة استخدامها في قواعدك. تسمح قواعد الأمان باستخدام الدوال المخصّصة. يشبه أسلوب كتابة الدوالّ المخصّصة إلى حدٍّ ما أسلوب كتابة JavaScript، ولكنّ دوالّ Firebase Security Rules مكتوبة بلغة خاصة بالمجال تفرض بعض القيود المهمة:
- يمكن أن تحتوي الدوالّ على عبارة
return
واحدة فقط. ولا يمكن أن تحتوي على أي منطق إضافي. على سبيل المثال، لا يمكنهم تنفيذ الحلقات أو الاتصال بخدمات خارجية. - يمكن للدوالّ الوصول تلقائيًا إلى الدوالّ والمتغيّرات من النطاق
الذي تم تعريفها فيه. على سبيل المثال، يمكن لدالة محدّدة ضمن
نطاق
service firebase.storage
الوصول إلى المتغيّرresource
، والدوالّ المدمَجة مثلget()
وexists()
لـ Cloud Firestore فقط. - يمكن أن تستدعي الدوالّ دوالّ أخرى، ولكن لا يمكنها التكرار. يقتصر إجمالي عمق تسلسل استدعاء الدوال البرمجية على 10.
- في الإصدار
rules2
، يمكن للدوالّ تحديد المتغيّرات باستخدام الكلمة الأساسيةlet
. يمكن أن تحتوي الدوال على أي عدد من روابط السماح، ولكن يجب أن تنتهي ببيان إرجاع.
يتم تعريف الدالة باستخدام الكلمة الرئيسية function
وتستخدِم وسيطات صفرية أو أكثر. على سبيل المثال، قد ترغب في دمج نوعي الشروط المستخدمَين
في الأمثلة أعلاه في دالة واحدة:
service firebase.storage {
match /b/{bucket}/o {
// 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 /images/{imageId} {
allow read, write: if signedInOrPublic();
}
match /mp3s/{mp3Ids} {
allow read: if signedInOrPublic();
}
}
}
إنّ استخدام الدوال في Firebase Security Rules يجعلها أكثر قابلية للصيانة مع تزايد تعقيد القواعد.
الخطوات التالية
بعد هذه المناقشة حول الشروط، أصبح لديك فهم أدق للقواعد وأصبحت مستعدًا لإجراء ما يلي:
تعرَّف على كيفية التعامل مع حالات الاستخدام الأساسية، وتعرَّف على سير العمل لتطوير القواعد واختبارها ونشرها:
- اكتب قواعد تتناول السيناريوهات الشائعة.
- يمكنك تعزيز معرفتك من خلال مراجعة المواقف التي يجب فيها رصد القواعد غير الآمنة وتجنُّبها.
- اختبِر القواعد باستخدام المحاكي Cloud Storage ومكتبة اختبارات قواعد الأمان المخصّصة.
- راجِع الطرق المتاحة لنشر Rules.