अपने 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, उपयोगकर्ताओं के क्रेडेंशियल की पुष्टि करता है. साथ ही, उपयोगकर्ता और भूमिका के हिसाब से ऐक्सेस देने वाले सिस्टम के लिए बुनियादी ढांचा उपलब्ध कराता है.

किसी भी डेटा को पढ़ने या लिखने से पहले, Rules मोबाइल/वेब क्लाइंट लाइब्रेरी से किए गए हर डेटाबेस अनुरोध का आकलन, आपके सुरक्षा नियमों के हिसाब से किया जाता है. अगर नियम, बताए गए किसी भी दस्तावेज़ पाथ का ऐक्सेस देने से मना करते हैं, तो पूरा अनुरोध अस्वीकार कर दिया जाता है.

Cloud Firestore Security Rules के बारे में ज़्यादा जानने के लिए, Cloud Firestore Security Rules का इस्तेमाल शुरू करना लेख पढ़ें.

एम्युलेटर इंस्टॉल करना

Cloud Firestore एम्युलेटर इंस्टॉल करने के लिए, Firebase सीएलआई का इस्तेमाल करें और यहां दिया गया कमांड चलाएं:

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 को मॉक करने की सुविधा देती है. इससे यूनिट टेस्ट करना काफ़ी आसान हो जाता है. इसके अलावा, लाइब्रेरी में एम्युलेटर के लिए कुछ खास सुविधाएं भी काम करती हैं. जैसे, सारा डेटा मिटाना. इन सुविधाओं की सूची नीचे दी गई है.
  • एम्युलेटर, क्लाइंट SDK टूल से मिले प्रोडक्शन Firebase Auth टोकन भी स्वीकार करेंगे. साथ ही, नियमों का आकलन भी करेंगे. इससे, इंटिग्रेशन और मैन्युअल टेस्ट में, आपके ऐप्लिकेशन को सीधे एम्युलेटर से कनेक्ट किया जा सकता है.

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

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

Firebase, सुरक्षा नियमों की यूनिट टेस्टिंग लाइब्रेरी को अपने JavaScript SDK टूल के वर्शन 9 और वर्शन 8, दोनों के साथ उपलब्ध कराता है. लाइब्रेरी एपीआई काफ़ी अलग हैं. हमारा सुझाव है कि आप 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.

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

  • initializeTestEnvironment को कॉल करके, RulesTestEnvironment को बनाना और कॉन्फ़िगर करना.
  • नियमों को ट्रिगर किए बिना टेस्ट डेटा सेट अप करना. इसके लिए, एक आसान तरीका इस्तेमाल किया जाता है, जिससे नियमों को कुछ समय के लिए बायपास किया जा सकता है, 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().doc('/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>

यह टेस्ट केस का उपयोगिता फ़ंक्शन है.

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

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 इंस्टेंस का इस्तेमाल, क्लाइंट SDK टूल के एपीआई (v9 मॉड्यूलर या v9 कंपैट) के साथ किया जा सकता है.

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

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

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

Firestore एम्युलेटर के अनुरोधों को मॉनिटर करने वाला टूल, जिसमें सुरक्षा नियमों के आकलन की जानकारी दिख रही है

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

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

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

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