अपने 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) पर चलेगा. एम्युलेटर पोर्ट को बदला जा सकता है. इसके लिए, अपनी firebase.json फ़ाइल के "emulators" सेक्शन में बदलाव करें:

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

एम्युलेटर चलाने से पहले

एम्युलेटर का इस्तेमाल शुरू करने से पहले, इन बातों का ध्यान रखें:

  • एम्युलेटर, शुरुआत में आपकी firebase.json फ़ाइल के firestore.rules फ़ील्ड में दिए गए नियमों को लोड करेगा. यह आपकी Cloud Firestore Security Rules वाली लोकल फ़ाइल का नाम ढूंढता है और उन नियमों को सभी प्रोजेक्ट पर लागू करता है. अगर आपने लोकल फ़ाइल पाथ नहीं दिया है या यहां बताए गए loadFirestoreRules तरीके का इस्तेमाल नहीं किया है, तो एम्युलेटर सभी प्रोजेक्ट को ऐसे प्रोजेक्ट के तौर पर ट्रीट करेगा जिनके लिए नियम खुले हैं.
  • ज़्यादातर Firebase SDK सीधे तौर पर एम्युलेटर के साथ काम करते हैं. हालांकि, सिर्फ़ @firebase/rules-unit-testing लाइब्रेरी, सुरक्षा नियमों में auth को मॉक करने की सुविधा देती है. इससे यूनिट टेस्ट करना बहुत आसान हो जाता है. इसके अलावा, लाइब्रेरी में एम्युलेटर के लिए कुछ खास सुविधाएं भी उपलब्ध हैं. जैसे, सभी डेटा मिटाना. इनकी जानकारी यहां दी गई है.
  • इम्यूलेटर, क्लाइंट एसडीके के ज़रिए दिए गए प्रोडक्शन Firebase Auth टोकन भी स्वीकार करेंगे. साथ ही, नियमों का आकलन करेंगे. इससे, इंटिग्रेशन और मैन्युअल टेस्ट में अपने ऐप्लिकेशन को सीधे तौर पर इम्यूलेटर से कनेक्ट किया जा सकेगा.

लोकल यूनिट टेस्ट चलाना

v9 JavaScript SDK की मदद से, लोकल यूनिट टेस्ट चलाना

Firebase, Security Rules की यूनिट टेस्टिंग लाइब्रेरी को अपने वर्शन 9 JavaScript SDK और वर्शन 8 SDK, दोनों के साथ डिस्ट्रिब्यूट करता है. लाइब्रेरी एपीआई काफ़ी अलग हैं. हम v9 टेस्टिंग लाइब्रेरी का इस्तेमाल करने का सुझाव देते हैं. यह ज़्यादा बेहतर है और इसे एम्युलेटर से कनेक्ट करने के लिए, कम सेटअप की ज़रूरत होती है. इस तरह, प्रोडक्शन संसाधनों का गलती से इस्तेमाल होने से सुरक्षित तरीके से बचा जा सकता है. पुराने सिस्टम के साथ काम करने की सुविधा के लिए, हम v8 टेस्टिंग लाइब्रेरी को उपलब्ध कराते रहेंगे.

स्थानीय तौर पर चलने वाले एम्युलेटर के साथ इंटरैक्ट करने के लिए, @firebase/rules-unit-testing मॉड्यूल का इस्तेमाल करें. अगर आपको टाइमआउट या ECONNREFUSED गड़बड़ियां मिलती हैं, तो दोबारा जांच लें कि एम्युलेटर चल रहा है या नहीं.

हमारा सुझाव है कि आप Node.js के नए वर्शन का इस्तेमाल करें, ताकि async/await नोटेशन का इस्तेमाल किया जा सके. आपको जिस भी व्यवहार की जाँच करनी है उसमें से ज़्यादातर में एसिंक्रोनस फ़ंक्शन शामिल होते हैं. साथ ही, टेस्टिंग मॉड्यूल को प्रॉमिस-आधारित कोड के साथ काम करने के लिए डिज़ाइन किया गया है.

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.

इंपोर्ट करने के बाद, यूनिट टेस्ट लागू करने के लिए ये काम करने होते हैं:

  • initializeTestEnvironment को कॉल करके, RulesTestEnvironment बनाना और उसे कॉन्फ़िगर करना.
  • नियमों को ट्रिगर किए बिना टेस्ट डेटा सेट अप करना. इसके लिए, एक आसान तरीका इस्तेमाल करें, ताकि नियमों को कुछ समय के लिए अनदेखा किया जा सके, RulesTestEnvironment.withSecurityRulesDisabled.
  • टेस्ट सुइट और हर टेस्ट के लिए, before/after हुक सेट अप करना. साथ ही, टेस्ट डेटा और एनवायरमेंट को क्लीन अप करने के लिए कॉल करना. जैसे, 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 बनता है. यह एक ऐसे क्लाइंट की तरह काम करता है जिसने पुष्टि किए बिना लॉग इन नहीं किया है. कॉन्टेक्स्ट से बनाए गए अनुरोधों में, 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()

ऐसे कॉन्टेक्स्ट के साथ टेस्ट सेटअप फ़ंक्शन चलाएं जो इस तरह काम करता है जैसे सुरक्षा नियम बंद कर दिए गए हों.

यह तरीका एक कॉलबैक फ़ंक्शन लेता है. यह Security-Rules-bypassing context लेता है और एक प्रॉमिस दिखाता है. प्रॉमिस के पूरा होने या अस्वीकार होने के बाद, कॉन्टेक्स्ट मिट जाएगा.

RulesTestEnvironment.cleanup()

यह तरीका, टेस्ट एनवायरमेंट में बनाए गए सभी RulesTestContexts को मिटा देता है. साथ ही, इससे जुड़े संसाधनों को भी मिटा देता है, ताकि टेस्ट को आसानी से बंद किया जा सके.

इस तरीके से, एम्युलेटर की स्थिति में कोई बदलाव नहीं होता. टेस्ट के बीच डेटा रीसेट करने के लिए, ऐप्लिकेशन के एम्युलेटर के लिए खास तौर पर तैयार किए गए, डेटा मिटाने के तरीके का इस्तेमाल करें.

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

यह टेस्ट केस यूटिलिटी फ़ंक्शन है.

यह फ़ंक्शन पुष्टि करता है कि एमुलेटर ऑपरेशन को रैप करने वाले दिए गए Promise को, सुरक्षा नियमों के किसी भी उल्लंघन के बिना हल किया जाएगा.

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

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

यह टेस्ट केस यूटिलिटी फ़ंक्शन है.

यह फ़ंक्शन पुष्टि करता है कि एम्युलेटर ऑपरेशन को रैप करने वाली दी गई प्रॉमिस को, सुरक्षा नियमों के उल्लंघन की वजह से अस्वीकार कर दिया जाएगा.

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

इम्यूलेटर के लिए खास तरीके

v9 SDK में टेस्ट करने के सामान्य तरीके और यूटिलिटी फ़ंक्शन भी देखें.

RulesTestEnvironment.clearFirestore() => Promise<void>

इस तरीके से, Firestore डेटाबेस में मौजूद उस डेटा को मिटाया जाता है जो Firestore एम्युलेटर के लिए कॉन्फ़िगर किए गए projectId से जुड़ा है.

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

यह तरीका, इस टेस्ट कॉन्टेक्स्ट के लिए Firestore इंस्टेंस को पाता है. Firebase JS Client SDK के इस इंस्टेंस का इस्तेमाल, Client SDK API (मॉड्यूलर v9 या v9 कंपैट) के साथ किया जा सकता है.

नियमों के आकलन को विज़ुअलाइज़ करना

Cloud Firestore एम्युलेटर की मदद से, Emulator Suite के यूज़र इंटरफ़ेस (यूआई) में क्लाइंट के अनुरोधों को देखा जा सकता है. इसमें Firebase के सुरक्षा नियमों के लिए, मूल्यांकन ट्रेसिंग भी शामिल है.

हर अनुरोध के लिए, आकलन के क्रम के बारे में ज़्यादा जानकारी देखने के लिए, Firestore > अनुरोध टैब खोलें.

Firestore Emulator Requests Monitor में, सुरक्षा के नियमों के आकलन को दिखाया गया है

टेस्ट रिपोर्ट जनरेट करना

जांचों का सुइट चलाने के बाद, जांच कवरेज रिपोर्ट ऐक्सेस की जा सकती हैं. इनमें यह दिखाया जाता है कि आपके हर सुरक्षा नियम का आकलन कैसे किया गया.

रिपोर्ट पाने के लिए, एम्युलेटर के चालू होने पर, उस पर मौजूद एंडपॉइंट को क्वेरी करें. ब्राउज़र के साथ काम करने वाले वर्शन के लिए, इस यूआरएल का इस्तेमाल करें:

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

इससे आपके नियमों को एक्सप्रेशन और सबएक्सप्रेशन में बांटा जाता है. इन पर कर्सर घुमाकर, ज़्यादा जानकारी देखी जा सकती है. जैसे, आकलन की संख्या और दिखाई गई वैल्यू. इस डेटा के रॉ JSON वर्शन के लिए, अपनी क्वेरी में यह यूआरएल शामिल करें:

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

एम्युलेटर और प्रोडक्शन के बीच अंतर

  1. आपको Cloud Firestore प्रोजेक्ट बनाने की ज़रूरत नहीं है. इम्यूलेटर, ऐक्सेस किए गए किसी भी इंस्टेंस को अपने-आप बना देता है.
  2. Cloud Firestore एम्युलेटर, सामान्य Firebase Authentication फ़्लो के साथ काम नहीं करता. इसके बजाय, हमने Firebase Test SDK में rules-unit-testing लाइब्रेरी में initializeTestApp() तरीका उपलब्ध कराया है. यह auth फ़ील्ड लेता है. इस तरीके का इस्तेमाल करके बनाया गया Firebase हैंडल, इस तरह काम करेगा जैसे कि आपने जिस भी इकाई की जानकारी दी है उसकी पुष्टि हो गई हो. null पास करने पर, इसे बिना पुष्टि किए उपयोगकर्ता के तौर पर माना जाएगा. उदाहरण के लिए, auth != null के नियम लागू नहीं होंगे.

ऐसी समस्याएं हल करना जिनके बारे में हमें पता है

Cloud Firestore एम्युलेटर का इस्तेमाल करते समय, आपको इन समस्याओं का सामना करना पड़ सकता है. अगर आपको कोई समस्या आ रही है, तो उसे हल करने के लिए यहां दिए गए निर्देशों का पालन करें. ये नोट, Security Rules की यूनिट टेस्टिंग लाइब्रेरी को ध्यान में रखकर लिखे गए हैं. हालांकि, सामान्य तरीके किसी भी 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 अलग-अलग मामलों में सही तरीके से अनुमति देता है / अनुमति नहीं देता है.