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

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

البدء السريع

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

فهم قواعد أمان Cloud Firestore

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

تتضمن قواعد أمان Cloud Firestore عنصرين:

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

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

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

يمكنك التعرّف على مزيد من المعلومات عن قواعد أمان Cloud Firestore في مقالة بدء استخدام قواعد أمان Cloud Firestore.

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

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

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 ويطبّق هذه القواعد على جميع مماثلة. إذا لم توفر مسار الملف المحلي أو تستخدم الملف في ما يخص loadFirestoreRules كما هو موضح أدناه، يتعامل المحاكي مع جميع المشروعات على أنها تحتوي على قواعد مفتوحة.
  • بينما معظم حِزم تطوير البرامج (SDK) لمنصة Firebase مباشرةً مع أدوات المحاكاة، لا تدعم مكتبة @firebase/rules-unit-testing محاكاة auth في "قواعد الأمان"، ما يجعل اختبارات الوحدات أسهل بكثير. بالإضافة إلى ذلك، تدعم المكتبة بعض الميزات الخاصة بالمحاكي مثل محو جميع البيانات كما هو موضح أدناه.
  • ستقبل أجهزة المحاكاة أيضًا الرموز المميزة لمصادقة Firebase للإنتاج من خلال حِزم تطوير البرامج (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

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

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

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 مرفقة.

استخدِم عنصر سياق الاختبار الذي تم عرضه في اختباراتك للوصول إلى أي محاكي. المثيلات التي تم ضبطها، بما في ذلك الأجهزة التي تم ضبطها باستخدام 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. وبدلاً من ذلك، في حزمة تطوير البرامج (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 فعلاً. إذا كانت قواعدك تطبّق إعداد الاختبار معقد، جرِّب استخدام RulesTestEnvironment.withSecurityRulesDisabled في الإعداد الخطوات، لذلك لن تؤدي عمليات القراءة والكتابة إلى عرض أخطاء PERMISSION_DENIED.

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