يستند هذا الدليل إلى دليل تعلُّم البنية الأساسية للغة Firebase Security Rules لعرض كيفية إضافة شروط إلى Firebase Security Rules في Cloud Storage.
الوحدة الأساسية في Cloud Storage Security Rules هي الشرط. الشرط هو تعبير منطقي يحدّد ما إذا كان يجب السماح بعملية معيّنة أو رفضها. بالنسبة إلى القواعد الأساسية، يعمل استخدام القيم الحرفية true وfalse كشروط بشكل جيد جدًا. لكنّ Firebase Security Rules لـ Cloud Storage
تمنحك طرقًا لكتابة شروط أكثر تعقيدًا يمكنها:
- التحقّق من مصادقة المستخدم
- التحقّق من صحة البيانات الواردة
المصادقة
Firebase Security Rules لـ Cloud Storage تتكامل مع Firebase Authentication لتوفير مصادقة قوية للمستخدمين في Cloud Storage. ويتيح ذلك التحكّم الدقيق في الوصول استنادًا إلى مطالبات رمز Firebase Authentication المميّز.
عندما ينفّذ مستخدم تمّت مصادقته طلبًا في Cloud Storage، يتم ملء المتغيّر
الـ request.auth برقم تعريف المستخدم uid
(request.auth.uid) بالإضافة إلى مطالبات رمز JWT المميّز لـ Firebase Authentication
(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 هي منح المستخدمين الفرديين أذونات دقيقة على ملفاتهم، بدءًا من تحميل صور الملف الشخصي إلى قراءة المستندات الخاصة.
بما أنّ الملفات في 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 Firebase Authentication يحتوي على معلومات إضافية عن أحد أعضاء المجموعة (مثل رقم تعريف المجموعة)
- تضمين معلومات المجموعة (مثل رقم تعريف المجموعة أو قائمة بـ
uids المصرّح بها) في البيانات الوصفية للملف
بعد تخزين هذه البيانات في الرمز المميّز أو البيانات الوصفية للملف، يمكن الرجوع إليها من داخل القاعدة:
// 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 المميّز. وفي ما عدا ذلك، سيكون
null. |
params |
map<string, string> | خريطة تحتوي على مَعلمات طلب البحث في الطلب. |
path |
path | `مسار` يمثّل المسار الذي يتم تنفيذ الطلب فيه.path |
resource |
map<string, string> | قيمة المورد الجديدة، لا تظهر إلا في طلبات write
|
time |
timestamp | طابع زمني يمثّل وقت الخادم الذي يتم فيه تقييم الطلب. |
تقييم المورد
عند تقييم القواعد، قد تحتاج أيضًا إلى تقييم البيانات الوصفية للملف الذي يتم تحميله أو تنزيله أو تعديله أو حذفه. يتيح لك ذلك إنشاء قواعد معقدة وقوية، مثل السماح فقط بتحميل الملفات التي تحتوي على أنواع محتوى معيّنة، أو حذف الملفات الأكبر من حجم معيّن فقط.
Firebase Security Rules لـ Cloud Storage توفّر البيانات الوصفية للملف في الكائن resource
، الذي يحتوي على أزواج المفاتيح والقيم للبيانات الوصفية التي تظهر في كائن
Cloud Storage. يمكن فحص هذه الخصائص في read أو
write لضمان سلامة البيانات.
في طلبات write (مثل عمليات التحميل وتعديلات البيانات الوصفية والحذف)، بالإضافة إلى الكائن resource الذي يحتوي على البيانات الوصفية للملف الذي يتوفّر حاليًا في مسار الطلب، يمكنك أيضًا استخدام الكائن request.resource الذي يحتوي على مجموعة فرعية من البيانات الوصفية للملف التي سيتم كتابتها إذا تم السماح بالكتابة. يمكنك استخدام هاتين القيمتَين لضمان سلامة البيانات أو فرض قيود التطبيق، مثل نوع الملف أو حجمه.
في ما يلي قائمة كاملة بالخصائص في الكائن resource:
| الموقع | النوع | الوصف |
|---|---|---|
name |
string | الاسم الكامل للكائن |
bucket |
string | اسم المستودع الذي يقيم فيه هذا الكائن. |
generation |
int | جيل كائن Google Cloud Storage لهذا الكائن. |
metageneration |
int | جيل البيانات الوصفية لكائن Google Cloud Storage لهذا الكائن. |
size |
int | حجم الكائن بالبايت. |
timeCreated |
timestamp | طابع زمني يمثّل وقت إنشاء الكائن. |
updated |
timestamp | طابع زمني يمثّل آخر وقت تم فيه تعديل الكائن. |
md5Hash |
string | تجزئة MD5 للكائن. |
crc32c |
string | تجزئة crc32c للكائن. |
etag |
string | علامة etag المرتبطة بهذا الكائن. |
contentDisposition |
string | طريقة عرض المحتوى المرتبطة بهذا الكائن. |
contentEncoding |
string | ترميز المحتوى المرتبط بهذا الكائن. |
contentLanguage |
string | لغة المحتوى المرتبطة بهذا الكائن. |
contentType |
string | نوع المحتوى المرتبط بهذا الكائن. |
metadata |
map<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)).data.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 console أو Firebase CLI تفعيل الأذونات لربط المنتجَين.
يمكنك إيقاف الميزة عن طريق إزالة دور IAM، كما هو موضّح في إدارة 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المتغيّر، وبالنسبة إلى Cloud Firestore فقط، يمكنها الوصول إلى الدوال المضمّنة مثلget()وexists(). - يمكن للدوال استدعاء دوال أخرى، ولكن لا يمكنها استدعاء نفسها. يقتصر إجمالي عمق مكدس الاستدعاء على 10.
- في الإصدار
rules2، يمكن للدوال تحديد المتغيّرات باستخدام الكلمة الرئيسيةlet. يمكن أن تحتوي الدوال على أي عدد من عمليات الربط باستخدام `let`، ولكن يجب أن تنتهي بعبارة `return`.
يتم تعريف الدالة باستخدام الكلمة الرئيسية 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 ومكتبة اختبار "قواعد الأمان" المخصّصة.
- راجِع الطرق المتاحة لـ نشر Security Rules.