अपने 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 सीएलआई का इस्तेमाल करें और नीचे दिया गया कमांड चलाएं:

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

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

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

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

स्थानीय तौर पर चलने वाले एमुलेटर के साथ इंटरैक्ट करने के लिए, @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.

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

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

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

यह तरीका एक कॉलबैक फ़ंक्शन लेता है, जो 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'), { ... });

एमुलेटर के हिसाब से तरीके

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

RulesTestEnvironment.clearFirestore() => Promise<void>

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

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

इस तरीके से, इस टेस्ट कॉन्टेक्स्ट के लिए Firestore इंस्टेंस मिलता है. दिखाए गए Firebase JS क्लाइंट SDK टूल के इंस्टेंस का इस्तेमाल, क्लाइंट SDK टूल के एपीआई (v9 मॉड्यूलर या v9 के साथ काम करने वाला) के साथ किया जा सकता है.

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

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

हर अनुरोध के लिए, आकलन का सिलसिलेवार तरीका देखने के लिए, Firestore > अनुरोध टैब खोलें.

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, अलग-अलग मामलों को सही तरीके से अनुमति देता है या अस्वीकार करता है.