اختبار قواعد أمان Cloud Firestore

أثناء إنشاء تطبيقك، قد تحتاج إلى حظر الوصول إلى قاعدة بيانات Cloud Firestore. ومع ذلك، قبل الإطلاق، ستحتاج إلى مزيد من التفاصيل الدقيقة Cloud Firestore Security Rules. باستخدام محاكي Cloud Firestore، بالإضافة إلى إنشاء النماذج الأولية واختبار الميزات والسلوك العام لتطبيقك، يمكنك كتابة اختبارات وحدات تتحقّق من سلوك Cloud Firestore Security Rules.

البدء السريع

وفي ما يتعلّق ببعض حالات الاختبار الأساسية التي تتضمّن قواعد بسيطة، يمكنك تجربة نموذج البدء السريع.

فهم Cloud Firestore Security Rules

نفِّذ Firebase Authentication مع Cloud Firestore Security Rules للاستخدام بدون خادم المصادقة والترخيص والتحقق من صحة البيانات عند استخدام واجهة مكتبات برامج الويب.

تشمل Cloud Firestore Security Rules جزأين:

  1. عبارة match لتحديد المستندات في قاعدة بياناتك
  2. تعبير allow يتحكّم في الوصول إلى هذه المستندات

يتحقق Firebase Authentication من صحة بيانات المستخدمين. بيانات اعتماد ويوفر الأساس وأنظمة الوصول القائمة على المستخدم والقائمة على الأدوار.

كل طلب قاعدة بيانات من مكتبة برامج الويب أو الأجهزة الجوّالة في Cloud Firestore يتم تقييمه وفقًا لقواعد الأمان لديك قبل قراءة أي بيانات أو كتابتها. وإذا كانت القواعد تمنع الوصول إلى أي من مسارات المستندات المحددة، فإن قاعدة فشل الطلب.

يمكنك الاطّلاع على مزيد من المعلومات حول Cloud Firestore Security Rules في مقالة بدء استخدام Cloud Firestore Security Rules.

تثبيت المحاكي

لتثبيت المحاكي Cloud Firestore، يمكنك استخدام Firebase CLI. وقم بتشغيل الأمر أدناه:

firebase setup:emulators:firestore

تشغيل المحاكي

ابدأ بإعداد مشروع Firebase في دليل العمل. هذا هو وهي الخطوة الأولى الشائعة عند استخدام واجهة سطر الأوامر في Firebase

firebase init

ابدأ المحاكي باستخدام الأمر التالي. سيتم تشغيل المحاكي حتى تغلق العملية:

firebase emulators:start --only firestore

وفي كثير من الأحيان، تريد بدء تشغيل المحاكي وتشغيل مجموعة تجريبية ثم إغلاق المحاكي بعد إجراء الاختبارات. يمكنك إجراء ذلك بسهولة باستخدام الأمر emulators:exec:

firebase emulators:exec --only firestore "./my-test-script.sh"

عند بدء تشغيل المحاكي، سيحاول تشغيله على منفذ تلقائي (8080). يمكنك تغيير منفذ المحاكي من خلال تعديل القسم "emulators" في ملف firebase.json:

{
  // ...
  "emulators": {
    "firestore": {
      "port": "YOUR_PORT"
    }
  }
}

قبل تشغيل المحاكي

قبل البدء في استخدام المحاكي، يجب مراعاة ما يلي:

  • سيحمّل المحاكي بشكل مبدئي القواعد المحدّدة في firestore.rules. الحقل في ملف firebase.json. وتتوقّع هذه الميزة اسم ملف محلي يحتوي على Cloud Firestore Security Rules وتطبّق هذه القواعد على جميع المشاريع. إذا لم توفر مسار الملف المحلي أو تستخدم الملف في ما يخص loadFirestoreRules كما هو موضح أدناه، يتعامل المحاكي مع جميع المشروعات على أنها تحتوي على قواعد مفتوحة.
  • على الرغم من أنّ معظم حِزم تطوير البرامج (SDK) لمنصة Firebase تعمل مع المحاكيات مباشرةً، لا تتيح سوى مكتبة @firebase/rules-unit-testing محاكاة auth في قواعد الأمان، ما يسهّل اختبارات الوحدة كثيرًا. بالإضافة إلى ذلك، تدعم المكتبة بعض الميزات الخاصة بالمحاكي مثل محو جميع البيانات كما هو موضح أدناه.
  • ستوافق المحاكيات أيضًا على الرموز المميّزة لإصدار الإصدار العلني من Firebase Auth المقدَّمة من خلال حِزم تطوير البرامج (SDK) للعملاء وتقيِّم القواعد وفقًا لذلك، ما يسمح بربط تطبيقك مباشرةً بالمحاكيات في عمليات الدمج والاختبارات اليدوية.

إجراء اختبارات الوحدة المحلية

إجراء اختبارات الوحدات المحلية باستخدام الإصدار 9 من حزمة تطوير البرامج (SDK) لJavaScript

يوزّع Firebase مكتبة اختبارات وحدات قواعد الأمان مع إصدارَيها. 9 JavaScript SDK والإصدار 8 من حزمة تطوير البرامج (SDK) الخاصة بها تساهم واجهات برمجة التطبيقات للمكتبة إلى حد كبير مختلفة. نقترح استخدام مكتبة اختبار الإصدار 9، والتي تكون أكثر سلاسة يتطلّب الأمر إعدادًا أقل للاتصال بالأجهزة المحاكية، وبالتالي يتم تجنُّب العرض غير المقصود بأمان استخدام موارد الإنتاج. وسنواصل توفير مكتبة اختبار الإصدار 8 للحفاظ على التوافق مع الإصدارات القديمة.

استخدام وحدة @firebase/rules-unit-testing للتفاعل مع المحاكي التي تعمل محليًا. إذا ظهرت لك أخطاء متعلّقة بانتهاء المهلة أو ECONNREFUSED أخطاء، يُرجى التحقّق مرة أخرى حقيقة أن المحاكي قيد التشغيل.

ننصحك بشدة باستخدام إصدار حديث من Node.js لتتمكّن من استخدام رمز async/await تقريبًا جميع السلوكيات التي قد ترغب في اختبارها تتضمن دوال غير متزامنة، وتم تصميم وحدة الاختبار للعمل مع رمز قائم على التعهدات.

تدرك مكتبة اختبار وحدة القواعد v9 دائمًا أدوات المحاكاة ولا يؤثر على موارد الإنتاج لديك.

يمكنك استيراد المكتبة باستخدام عبارات الاستيراد النموذجية للإصدار v9. على سبيل المثال:

import {
  assertFails,
  assertSucceeds,
  initializeTestEnvironment
} from "@firebase/rules-unit-testing"

// Use `const { … } = require("@firebase/rules-unit-testing")` if imports are not supported
// Or we suggest `const testing = require("@firebase/rules-unit-testing")` if necessary.

بعد الاستيراد، يتضمّن تنفيذ اختبارات الوحدة ما يلي:

  • إنشاء RulesTestEnvironment وضبطه من خلال طلب initializeTestEnvironment
  • إعداد بيانات الاختبار بدون تشغيل القواعد، واستخدام الراحة تسمح لك بتجاوزها مؤقتًا، RulesTestEnvironment.withSecurityRulesDisabled
  • جارٍ إعداد مجموعة الاختبار ولكل اختبار قبل/بعد عناصر المحاذاة مع طلبات استدعاء تنظيف بيانات الاختبار والبيئة، مثل RulesTestEnvironment.cleanup() أو RulesTestEnvironment.clearFirestore().
  • تنفيذ حالات الاختبار التي تحاكي حالات المصادقة باستخدام RulesTestEnvironment.authenticatedContext و RulesTestEnvironment.unauthenticatedContext

الطرق الشائعة ووظائف المنفعة

اطّلِع أيضًا على طرق الاختبار الخاصة بالمحاكي في حزمة تطوير البرامج (SDK) من الإصدار 9.

initializeTestEnvironment() => RulesTestEnvironment

تعمل هذه الدالة على إعداد بيئة اختبار لاختبار وحدة القواعد. الاتصال بهذا الاسم للعمل أولاً من أجل إعداد الاختبار. يتطلب التنفيذ الناجح توفر المحاكيات الجري.

تقبل الدالة كائنًا اختياريًا يحدد TestEnvironmentConfig، والتي يمكن أن تتألف من رقم تعريف المشروع وإعدادات ضبط المحاكي.

let testEnv = await initializeTestEnvironment({
  projectId: "demo-project-1234",
  firestore: {
    rules: fs.readFileSync("firestore.rules", "utf8"),
  },
});

RulesTestEnvironment.authenticatedContext({ user_id: string, tokenOptions?: TokenOptions }) => RulesTestContext

تنشئ هذه الطريقة RulesTestContext، الذي يعمل كرمز مصادق عليه مستخدم المصادقة. الطلبات التي يتم إنشاؤها من خلال السياق المعروض ستتضمّن نموذجًا تجريبيًا تم إرفاق الرمز المميّز للمصادقة. يمكنك اختياريًا تمرير عنصر يحدّد المطالبات المخصّصة أو حمولات بيانات أساسية للرمز المميز للمصادقة.

استخدِم عنصر سياق الاختبار الذي تم عرضه في اختباراتك للوصول إلى أي محاكي. المثيلات التي تم ضبطها، بما في ذلك الأجهزة التي تم ضبطها باستخدام initializeTestEnvironment.

// Assuming a Firestore app and the Firestore emulator for this example
import { setDoc } from "firebase/firestore";

const alice = testEnv.authenticatedContext("alice", {  });
// Use the Firestore instance associated with this context
await assertSucceeds(setDoc(alice.firestore(), '/users/alice'), { ... });

RulesTestEnvironment.unauthenticatedContext() => RulesTestContext

تنشئ هذه الطريقة RulesTestContext، الذي يتصرف كعميل لم يتم تسجيل الدخول عبر المصادقة. لن يتم إرفاق علامات Firebase Auth بطلبات الربط التي تم إنشاؤها من خلال السياق الذي تم إرجاعه.

استخدِم عنصر سياق الاختبار الذي تم عرضه في اختباراتك للوصول إلى أي محاكي. المثيلات التي تم ضبطها، بما في ذلك الأجهزة التي تم ضبطها باستخدام initializeTestEnvironment.

// Assuming a Cloud Storage app and the Storage emulator for this example
import { getStorage, ref, deleteObject } from "firebase/storage";

const alice = testEnv.unauthenticatedContext();

// Use the Cloud Storage instance associated with this context
const desertRef = ref(alice.storage(), 'images/desert.jpg');
await assertSucceeds(deleteObject(desertRef));

RulesTestEnvironment.withSecurityRulesDisabled()

يمكنك تنفيذ دالة إعداد اختبار باستخدام سياق يعمل كما لو كانت قواعد الأمان متوقفة.

تأخذ هذه الطريقة دالة استدعاء، والتي تأخذ مسار تجاوز قواعد الأمان والسياق ويقدم الوعد. سيتم تلف السياق بعد تقديم الوعد يحل / يرفض.

RulesTestEnvironment.cleanup()

تؤدي هذه الطريقة إلى إتلاف كل RulesTestContexts التي تم إنشاؤها في بيئة الاختبار وينظف الموارد الأساسية، مما يسمح بمخرج نظيف.

ولا تؤدي هذه الطريقة إلى تغيير حالة أدوات المحاكاة بأي شكل من الأشكال. لإعادة ضبط البيانات بين الاختبارات، استخدم طريقة البيانات الواضحة الخاصة بمحاكي التطبيق.

assertSucceeds(pr: Promise<any>)) => Promise<any>

هذه دالة مساعدة حالة اختبار.

تؤكد الدالة أن Promise المقدمة تعمل على إحاطة عملية المحاكي ستتم حله بدون أي انتهاكات لقواعد الأمان.

await assertSucceeds(setDoc(alice.firestore(), '/users/alice'), { ... });

assertFails(pr: Promise<any>)) => Promise<any>

هذه وظيفة أداة لحالة الاختبار.

تؤكد الدالة أن Promise المقدمة تعمل على إحاطة عملية المحاكي سيتم رفضه بسبب انتهاك "قواعد الأمان".

await assertFails(setDoc(alice.firestore(), '/users/bob'), { ... });

الطرق الخاصة بالمحاكي

يُرجى الاطّلاع أيضًا على أساليب الاختبار الشائعة ووظائف الأداة المساعدة في الإصدار 9 من حزمة تطوير البرامج (SDK).

RulesTestEnvironment.clearFirestore() => Promise<void>

تعمل هذه الطريقة على محو البيانات في قاعدة بيانات Firestore التي تنتمي إلى projectId الذي تم ضبطه لمحاكي Firestore.

RulesTestContext.firestore(settings?: Firestore.FirestoreSettings) => Firestore;

تحصل هذه الطريقة على مثيل Firestore لسياق الاختبار هذا. تم إرجاع يمكن استخدام مثيل حزمة تطوير البرامج (SDK) لعميل JavaScript JS مع واجهات برمجة تطبيقات حزمة تطوير البرامج (SDK) للعميل (الإصدار 9 المكوَّن من وحدات أو v9 compat).

عرض تقييمات القواعد بصريًا

يتيح لك محاكي "Cloud Firestore" عرض طلبات العميل بشكل مرئي واجهة مستخدم مجموعة Emulator، بما في ذلك تتبُّع التقييم لقواعد أمان Firebase.

افتح علامة التبويب Firestore > الطلبات لعرض تسلسل التقييم المفصّل لكل طلب.

أداة مراقبة طلبات المحاكي في Firestore تعرِض تقييمات قواعد الأمان

إنشاء تقارير الاختبار

بعد إجراء مجموعة من الاختبارات، يمكنك الوصول إلى الاختبار تقارير التغطية التي توضح كيفية تقييم كل قاعدة من قواعد الأمان.

للحصول على التقارير، يمكنك الاستعلام عن نقطة نهاية مكشوفة على المحاكي أثناء إنه قيد التشغيل. للحصول على نسخة متوافقة مع المتصفّحات، استخدِم عنوان URL التالي:

http://localhost:8080/emulator/v1/projects/<project_id>:ruleCoverage.html

يقسِّم هذا القواعد إلى تعبيرات وتعبيرات فرعية يمكنك تمرير الماوس لمزيد من المعلومات، بما في ذلك عدد التقييمات والقيم عاد. في ما يتعلّق بإصدار JSON الأولي من هذه البيانات، أدرِج عنوان URL التالي. في استعلامك:

http://localhost:8080/emulator/v1/projects/<project_id>:ruleCoverage

الاختلافات بين المحاكي والإنتاج

  1. لست بحاجة إلى إنشاء مشروع Cloud Firestore بشكل صريح. ينشئ المحاكي تلقائيًا أي نسخة يتم الوصول إليها.
  2. لا يعمل محاكي Cloud Firestore مع مسار Firebase Authentication العادي. وبدلاً من ذلك، في حزمة تطوير البرامج (SDK) الاختبارية لاختبار Firebase، قدمنا الطريقة initializeTestApp() في rules-unit-testing، والذي يأخذ الحقل auth. تم إنشاء اسم حساب Firebase فإن استخدام هذه الطريقة سيعمل كما لو تمت مصادقتها بنجاح وأي كيان تقدمه. إذا نجحت في اجتياز null، سيعمل كـ مستخدم لم تتم مصادقته (لن تعمل قواعد auth != null مثلاً)

تحديد المشاكل المعروفة وحلّها

أثناء استخدام محاكي Cloud Firestore، قد تواجه الصعوبات التالية المعروفة. اتبع الإرشادات أدناه لتحري أي سلوك غير منتظم قمت به وإصلاحها التي يواجهونها. تمت كتابة هذه الملاحظات باستخدام اختبار وحدة "قواعد الأمان" هذه التطبيقات، ولكن يمكن تطبيق الأساليب العامة على أي حزمة تطوير برامج (SDK) لمنصّة Firebase.

سلوك الاختبار غير متسق

إذا كانت اختباراتك تجتاز وتفشل أحيانًا، حتى بدون أي تغييرات على الاختبارات نفسها، فقد تحتاج إلى التحقق من أنها متسلسلة بشكل صحيح. تكون معظم التفاعلات مع المحاكي غير متزامنة، لذا تحقق جيدًا من أن جميع تسلسل التعليمة البرمجية غير المتزامنة بشكل صحيح. يمكنك إصلاح التسلسل عن طريق أو سلسلة الوعود أو استخدام ترميز await بكل حرية.

وعلى وجه الخصوص، راجِع العمليات غير المتزامنة التالية:

  • إعداد قواعد الأمان، باستخدام initializeTestEnvironment مثلاً.
  • قراءة البيانات وكتابتها باستخدام، مثل db.collection("users").doc("alice").get()
  • تأكيدات التشغيل، بما في ذلك assertSucceeds وassertFails.

تجتاز الاختبارات في المرة الأولى فقط التي يتم فيها تحميل المحاكي

المحاكي في وضع الحالة. يخزن جميع البيانات المكتوبة عليه في الذاكرة، ويتم فقدان أي بيانات عند إيقاف تشغيل المحاكي. إذا كنت تشغّل عدة مقابل نفس معرف المشروع، فيمكن لكل اختبار إنتاج بيانات قد التأثير على الاختبارات اللاحقة. يمكنك استخدام أي من الطرق التالية تجاوز هذا السلوك:

  • استخدم معرّفات مشروع فريدة لكل اختبار. يُرجى العلم أنّه إذا اخترت إجراء ذلك، ستحتاج إلى استدعاء initializeTestEnvironment كجزء من كل اختبار، ولا يتم تحميل القواعد تلقائيًا إلا بمعرّف المشروع التلقائي.
  • إعادة تنظيم الاختبارات حتى لا تتفاعل مع البيانات المكتوبة سابقًا (على سبيل المثال، استخدِم مجموعة مختلفة لكل اختبار).
  • حذف جميع البيانات المكتوبة أثناء الاختبار.

عملية الإعداد التجريبية معقّدة للغاية.

عند إعداد الاختبار، قد تحتاج إلى تعديل البيانات بطريقة Cloud Firestore Security Rules لا يسمحون بذلك فعليًا. إذا كانت قواعدك تطبّق إعداد الاختبار معقد، جرِّب استخدام RulesTestEnvironment.withSecurityRulesDisabled في الإعداد الخطوات، لذلك لن تؤدي عمليات القراءة والكتابة إلى عرض أخطاء PERMISSION_DENIED.

بعد ذلك، يمكن أن يؤدي الاختبار إلى إجراء العمليات كمشروع تمت مصادقته أو لم تتم مصادقته مستخدم يستخدم RulesTestEnvironment.authenticatedContext وunauthenticatedContext على التوالي. يتيح لك ذلك التحقّق من أنّ Cloud Firestore Security Rules يسمح أو يرفض. الحالات المختلفة بشكل صحيح.