استخدام الشروط في قواعد أمان Firebase Cloud Storage

يستند هذا الدليل إلى البنية الأساسية لدليل لغة 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) بالإضافة إلى مطالبات 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 هي منح مستخدمين فرديين أذونات دقيقة على ملفاتهم، بدءًا من تحميل صور الملفات الشخصية ووصولاً إلى قراءة المستندات الخاصة.

نظرًا لأن الملفات في 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 خريطة<string, string> عندما يكون المستخدم مسجِّلاً الدخول، يقدّم uid، وهو المعرّف الفريد للمستخدم، token، وهو خريطة لمطالبات Firebase Authentication JWT. بخلاف ذلك، سيكون null.
params خريطة<string, string> خريطة تحتوي على مَعلمات طلب البحث الخاصة بالطلب
path المسار تمثّل هذه السمة path المسار الذي يتم تنفيذه الطلب. تنفيذها في.
resource خريطة<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 السلسلة العلامة الإلكترونية المرتبطة بهذا الكائن.
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، والدوال المدمجة لـ 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 Security Rules يجعلها أكثر قابلية للصيانة نظرًا لتعقيدها من قواعدك في ازدياد.

الخطوات التالية

بعد هذه المناقشة للشروط، تكون لديك فكرة أكثر تعقيدًا فهم القواعد وهم مستعدون لما يلي:

تعلُّم كيفية التعامل مع حالات الاستخدام الأساسية وتعلُّم سير العمل لتطوير اختبار القواعد ونشرها: