قوانین امنیتی 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 CLI است.

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 تولیدی ارائه شده از طریق Client SDK را می پذیرند و قوانین را بر اساس آن ارزیابی می کنند، که اجازه می دهد برنامه شما را مستقیماً به شبیه سازها در یکپارچه سازی و آزمایش های دستی متصل کنید.

تست های واحد محلی را اجرا کنید

تست های واحد محلی را با v9 JavaScript SDK اجرا کنید

Firebase یک کتابخانه تست واحد قوانین امنیتی را با نسخه 9 JavaScript SDK و نسخه 8 SDK خود توزیع می کند. APIهای کتابخانه به طور قابل توجهی متفاوت هستند. ما کتابخانه آزمایشی v9 را توصیه می‌کنیم که ساده‌تر است و برای اتصال به شبیه‌سازها به تنظیمات کمتری نیاز دارد و بنابراین از استفاده تصادفی از منابع تولید جلوگیری می‌کند. برای سازگاری به عقب، ما همچنان کتابخانه آزمایش v8 را در دسترس قرار می دهیم.

از ماژول @firebase/rules-unit-testing برای تعامل با شبیه ساز که به صورت محلی اجرا می شود استفاده کنید. اگر با وقفه زمانی یا خطاهای ECONNREFUSED مواجه شدید، دوباره بررسی کنید که شبیه ساز واقعاً در حال اجرا است.

ما قویاً توصیه می کنیم از نسخه اخیر Node.js استفاده کنید تا بتوانید از نماد async/await استفاده کنید. تقریباً تمام رفتارهایی که ممکن است بخواهید آزمایش کنید شامل توابع ناهمزمان است و ماژول تست برای کار با کد مبتنی بر Promise طراحی شده است.

کتابخانه v9 Rules Unit Testing همیشه از شبیه سازها آگاه است و هرگز منابع تولید شما را لمس نمی کند.

شما کتابخانه را با استفاده از دستورات واردات مدولار 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 .
  • راه‌اندازی داده‌های آزمایشی بدون راه‌اندازی Rules، با استفاده از روشی راحت که به شما امکان می‌دهد موقتاً آنها را دور بزنید، RulesTestEnvironment.withSecurityRulesDisabled .
  • راه‌اندازی مجموعه آزمایشی و قلاب‌های هر آزمون قبل و بعد از آن با فراخوانی برای پاکسازی داده‌های آزمایش و محیط، مانند RulesTestEnvironment.cleanup() یا RulesTestEnvironment.clearFirestore() .
  • اجرای موارد آزمایشی که حالت‌های احراز هویت را با استفاده از RulesTestEnvironment.authenticatedContext و RulesTestEnvironment.unauthenticatedContext تقلید می‌کنند.

روش های رایج و توابع سودمند

همچنین روش‌های آزمایش مخصوص شبیه‌ساز را در v9 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 ایجاد می‌کند که مانند کلاینت‌هایی عمل می‌کند که از طریق Authentication وارد نشده‌اند. درخواست‌هایی که از طریق زمینه بازگشتی ایجاد می‌شوند، نشانه‌های 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()

یک تابع راه اندازی آزمایشی را با زمینه ای اجرا کنید که به گونه ای رفتار می کند که گویی قوانین امنیتی غیرفعال شده اند.

این متد یک تابع callback می گیرد که زمینه Security-Rules-bypassing را می گیرد و یک وعده را برمی گرداند. پس از رفع / رد قول، زمینه از بین می رود.

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'), { ... });

روش های خاص شبیه ساز

همچنین روش‌های آزمایش رایج و توابع کاربردی را در v9 SDK ببینید.

RulesTestEnvironment.clearFirestore() => Promise<void>

این روش داده هایی را در پایگاه داده Firestore که به projectId پیکربندی شده برای شبیه ساز Firestore تعلق دارد پاک می کند.

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

این روش یک نمونه Firestore برای این زمینه آزمایشی دریافت می کند. نمونه Firebase JS Client SDK برگشتی را می توان با APIهای SDK کلاینت (v9 مدولار یا v9 compat) استفاده کرد.

ارزیابی قوانین را تجسم کنید

شبیه ساز Cloud Firestore به شما امکان می دهد درخواست های مشتری را در رابط کاربری Emulator Suite تجسم کنید، از جمله ردیابی ارزیابی برای قوانین امنیتی Firebase.

برای مشاهده توالی ارزیابی دقیق برای هر درخواست، برگه Firestore > Requests را باز کنید.

مانیتور درخواست‌های شبیه‌ساز 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 کار نمی کند. در عوض، در Firebase Test SDK، ما متد initializeTestApp() را در کتابخانه rules-unit-testing ارائه کرده‌ایم که یک فیلد auth می‌گیرد. دسته Firebase که با استفاده از این روش ایجاد شده است، طوری رفتار می کند که گویی با موفقیت به عنوان هر موجودی که ارائه می کنید، احراز هویت شده است. اگر null را پاس کنید، مانند یک کاربر احراز هویت نشده رفتار می کند (مثلاً auth != null با شکست مواجه می شوند).

عیب یابی مشکلات شناخته شده

همانطور که از شبیه ساز Cloud Firestore استفاده می کنید، ممکن است با مشکلات شناخته شده زیر مواجه شوید. برای عیب یابی هرگونه رفتار نامنظمی که تجربه می کنید، راهنمایی های زیر را دنبال کنید. این یادداشت ها با در نظر گرفتن کتابخانه تست واحد قوانین امنیتی نوشته شده اند، اما رویکردهای کلی برای هر Firebase SDK قابل اجرا هستند.

رفتار آزمون ناسازگار است

اگر آزمون‌های شما گهگاه با موفقیت پشت سر می‌گذارند و ناموفق هستند، حتی بدون هیچ تغییری در خود آزمون‌ها، ممکن است لازم باشد بررسی کنید که آنها به درستی ترتیب‌بندی شده‌اند. بیشتر تعاملات با شبیه ساز ناهمزمان هستند، بنابراین دوبار بررسی کنید که تمام کدهای همگام به درستی توالی شده باشند. می‌توانید توالی‌بندی را با زنجیره‌ای کردن وعده‌ها یا با استفاده آزادانه از نماد 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 شما موارد مختلف را به درستی اجازه می دهد / رد می کند.