يستند هذا الدليل إلى دليل التعرّف على البنية الأساسية للغة قواعد أمان Firebase لتوضيح كيفية إضافة شروط إلى قواعد أمان Firebase الخاصة بخدمة Cloud Storage.
الوحدة الأساسية لقواعد أمان Cloud Storage هي الشرط. الشرط هو تعبير منطقي يحدد ما إذا كان يجب السماح بعملية معينة أو رفضها. بالنسبة إلى القواعد الأساسية، استخدِم القيم الحرفية true
وfalse
لأنّ الشروط تعمل بشكل جيد تمامًا. إلا أنّ لغة "قواعد أمان Firebase" للغة Cloud Storage
تمنحك طُرقًا لكتابة شروط أكثر تعقيدًا يمكنها أن:
- التحقق من مصادقة المستخدم
- التحقق من صحة البيانات الواردة
المصادقة
تتكامل قواعد أمان Firebase المخصصة لخدمة Cloud Storage مع مصادقة Firebase لتوفير مصادقة فعّالة مستندة إلى المستخدم لخدمة Cloud Storage. ويتيح ذلك التحكم الدقيق في الوصول بناءً على مطالبات الرمز المميز لمصادقة Firebase.
عندما ينفّذ مستخدم تمت مصادقته طلبًا مقابل Cloud Storage،
تتم تعبئة المتغيّر request.auth
بـ uid
(request.auth.uid
) الخاص بالمستخدم، بالإضافة إلى مطالبات JWT
(request.auth.token
) لمصادقة Firebase.
بالإضافة إلى ذلك، عند استخدام المصادقة المخصّصة، تظهر مطالبات إضافية في الحقل 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 يحتوي على معلومات إضافية حول عضو في المجموعة (مثل رقم تعريف المجموعة)
- يمكنك تضمين معلومات المجموعة (مثل رقم تعريف المجموعة أو قائمة
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 في العنصر request.auth
كما هو موضّح أعلاه،
يحتوي المتغيّر request
على مسار الملف الذي يتم فيه تنفيذ الطلب والوقت الذي يتم فيه استلام الطلب وقيمة resource
الجديدة إذا كان الطلب مكتوبًا.
يحتوي عنصر request
أيضًا على المعرّف الفريد للمستخدم
وحمولة "مصادقة Firebase" في العنصر request.auth
، وسيتم
توضيح ذلك بمزيد من الشرح في قسم الأمان المستند إلى المستخدم
في المستندات.
في ما يلي قائمة كاملة بالسمات في الكائن request
:
الموقع | Type | الوصف |
---|---|---|
auth |
خريطة<string, string> | عندما يكون المستخدم مسجّلاً الدخول، يقدّم uid ، المعرّف الفريد للمستخدم، وtoken ، خريطة لمطالبات JWT لمصادقة Firebase. وفي حال عدم إجراء ذلك، سيكون
null . |
params |
خريطة<string, string> | خريطة تحتوي على مَعلمات طلب البحث الخاصة بالطلب |
path |
المسار | تمثّل هذه السمة path المسار الذي يتم تنفيذ الطلب فيه. |
resource |
خريطة<string, string> | لا تتوفّر قيمة المورد الجديدة إلا في طلبات write .
|
time |
الطابع الزمني | طابع زمني يمثّل وقت الخادم الذي يتم تقييم الطلب فيه |
تقييم الموارد
عند تقييم القواعد، ننصحك أيضًا بتقييم البيانات الوصفية للملف الذي يتم تحميله أو تنزيله أو تعديله أو حذفه. ويتيح لك ذلك إنشاء قواعد معقدة وفعالة تؤدي فقط إلى السماح بتحميل ملفات ذات أنواع محتوى معيّنة، أو حذف ملفات يزيد حجمها عن حجم معيّن فقط.
توفّر قواعد أمان Firebase في Cloud Storage البيانات الوصفية للملفات في كائن resource
الذي يحتوي على أزواج المفتاح/القيمة من البيانات الوصفية المعروضة في عنصر Cloud Storage. يمكن فحص هذه السمات في طلبات read
أو
write
لضمان سلامة البيانات.
في طلبات write
(مثل عمليات التحميل وتعديل البيانات الوصفية وعمليات الحذف)، بالإضافة إلى العنصر resource
الذي يحتوي على البيانات الوصفية للملف
المتوفّر حاليًا في مسار الطلب، يمكنك أيضًا استخدام العنصر request.resource
الذي يحتوي على مجموعة فرعية من البيانات الوصفية للملف المطلوب كتابتها إذا كانت إمكانية الكتابة مسموحًا بها. يمكنك استخدام هاتين القيمتين لضمان سلامة البيانات
أو فرض قيود على التطبيق مثل نوع الملف أو حجمه.
في ما يلي قائمة كاملة بالسمات في الكائن resource
:
الموقع | Type | الوصف |
---|---|---|
name |
سلسلة | الاسم الكامل للعنصر |
bucket |
سلسلة | اسم الحزمة التي يتوفّر فيها هذا العنصر |
generation |
int | عملية إنشاء العناصر في Google Cloud Storage لهذا العنصر. |
metageneration |
int | إنشاء البيانات الوصفية للكائن Google Cloud Storage لهذا العنصر. |
size |
int | حجم العنصر بالبايت. |
timeCreated |
الطابع الزمني | طابع زمني يمثّل وقت إنشاء العنصر |
updated |
الطابع الزمني | طابع زمني يمثّل آخر مرة تم فيها تعديل العنصر |
md5Hash |
سلسلة | تجزئة MD5 للكائن. |
crc32c |
سلسلة | تجزئة crc32c للكائن. |
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 الأولى التي تستخدم وظائف Cloud Firestore هذه، سيُطلب منك في وحدة تحكُّم Firebase أو واجهة سطر الأوامر في Firebase تفعيل الأذونات لربط المنتجين.
يمكنك إيقاف الميزة عن طريق إزالة دور "إدارة الهوية وإمكانية الوصول"، كما هو موضّح في إدارة قواعد أمان Firebase ونشرها.
التحقق من صحة البيانات
يمكن أيضًا استخدام قواعد أمان Firebase المخصصة لخدمة 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 أصبحت أكثر تعقيدًا، فقد تحتاج إلى التفاف مجموعات من الشروط في الدوال التي يمكنك إعادة استخدامها عبر مجموعة القواعد. تدعم قواعد الأمان الوظائف المخصصة. تشبه بنية الدوال المخصصة إلى حد ما JavaScript، ولكن دوال قواعد أمان Firebase مكتوبة بلغة محددة للنطاق هناك بعض القيود المهمة:
- يمكن أن تحتوي الدوال على عبارة
return
واحدة فقط. ولا يمكن أن تحتوي على أي منطق إضافي. على سبيل المثال، لا يمكنها تنفيذ التكرارات الحلقية أو استدعاء الخدمات الخارجية. - يمكن للدوال الوصول تلقائيًا إلى الدوال والمتغيرات من
النطاق الذي تم تحديدها فيه. على سبيل المثال، يمكن لدالة محدّدة ضمن النطاق
service firebase.storage
الوصول إلى المتغيّرresource
، وفي Cloud Firestore فقط، يمكن للدوال المضمّنة مثلget()
وexists()
. - قد تستدعي الدوال دوال أخرى ولكنها قد لا تتكرر. يقتصر إجمالي عمق تكديس الاستدعاءات على 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" إلى زيادة إمكانية صيانتها مع تزايد تعقيد القواعد.
الخطوات اللاحقة
بعد هذه المناقشة للشروط، أصبح لديك فهمًا أكثر تعقيدًا للقواعد وأصبحت جاهزًا لإجراء ما يلي:
تعرّف على كيفية التعامل مع حالات الاستخدام الأساسية وتعرّف على سير العمل لتطوير القواعد واختبارها ونشرها:
- اكتب القواعد التي تعالج السيناريوهات الشائعة.
- يمكنك الاستفادة من معرفتك من خلال مراجعة المواقف التي يجب فيها اكتشاف القواعد غير الآمنة وتجنُّبها.
- اختبِر القواعد باستخدام محاكي Cloud Storage ومكتبة اختبار قواعد الأمان المخصّصة.
- راجِع الطرق المتاحة لنشر القواعد.