يستند هذا الدليل إلى دليل التعرّف على بنية الجملة الأساسية للغة 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 |
map<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 |
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)).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 CLI تفعيل الأذونات لربط المنتجَين.
يمكنك إيقاف الميزة من خلال إزالة دور في "إدارة الهوية وإمكانية الوصول"، كما هو موضّح في مقالة إدارة ونشر 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
. يمكن أن تحتوي الدوال على أي عدد من عمليات الربط باستخدام 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.