डेटा को सुरक्षित तरीके से क्वेरी करें

इस पेज पर, सुरक्षा नियमों को व्यवस्थित करने और सुरक्षा नियमों के लिए शर्तें लिखने के बारे में बताया गया है. इससे यह समझने में मदद मिलती है कि Cloud Firestore Security Rules, क्वेरी के साथ कैसे इंटरैक्ट करते हैं. इसमें इस बात पर ज़्यादा ध्यान दिया जाता है कि सुरक्षा के नियम, आपकी लिखी जाने वाली क्वेरी पर कैसे असर डालते हैं. साथ ही, इसमें यह भी बताया जाता है कि यह कैसे पक्का किया जाए कि आपकी क्वेरी में सुरक्षा के नियमों जैसी ही पाबंदियों का इस्तेमाल किया जाए. इस पेज पर, सुरक्षा से जुड़े नियम लिखने का तरीका भी बताया गया है. इससे limit और orderBy जैसी क्वेरी प्रॉपर्टी के आधार पर, क्वेरी को अनुमति दी जा सकती है या अस्वीकार किया जा सकता है.

एआई असिस्टेंस पाने के लिए, यहां दिए गए प्रॉम्प्ट को अपने एआई कोडिंग एजेंट (जैसे, Android Studio में Gemini, Antigravity, Claude Code, Codex, और Cursor) में कॉपी करें. प्रॉम्प्ट को अपनी पसंद के मुताबिक बनाया जा सकता है. साथ ही, एजेंट के साथ मिलकर उसमें बदलाव किया जा सकता है. इंस्टॉल करने के बारे में ज़्यादा जानकारी के लिए, Firebase एजेंट स्किल पर जाएं.

Help me use Firebase in my app.
1. Make sure that **Firebase agent skills** are installed and updated. For Claude Code, Codex, or Cursor agents, help me install the Firebase plugin. For other agents, run `npx skills add firebase/agent-skills`. Always try to use **Firebase agent skills** for Firebase-related tasks.
2. Help me write, validate, and deploy Firebase Security Rules to protect my app's Firestore data.

नियम, फ़िल्टर नहीं होते

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

क्वेरी और सुरक्षा के नियम

नीचे दिए गए उदाहरणों से पता चलता है कि आपको अपनी क्वेरी इस तरह लिखनी चाहिए कि वे सुरक्षा नियमों की शर्तों के मुताबिक हों.

auth.uid के आधार पर दस्तावेज़ों को सुरक्षित करना और उनसे जुड़े सवाल पूछना

यहां दिए गए उदाहरण में, सुरक्षा नियम से सुरक्षित किए गए दस्तावेज़ों को वापस पाने के लिए क्वेरी लिखने का तरीका बताया गया है. मान लें कि आपके पास एक ऐसा डेटाबेस है जिसमें story दस्तावेज़ों का कलेक्शन है:

/stories/{storyid}

{
  title: "A Great Story",
  content: "Once upon a time...",
  author: "some_auth_id",
  published: false
}

title और content फ़ील्ड के अलावा, हर दस्तावेज़ में author और published फ़ील्ड भी सेव होते हैं. इनका इस्तेमाल, ऐक्सेस कंट्रोल के लिए किया जाता है. इन उदाहरणों में यह माना गया है कि ऐप्लिकेशन, Firebase से पुष्टि करने की सुविधा का इस्तेमाल करके, author फ़ील्ड को दस्तावेज़ बनाने वाले उपयोगकर्ता के यूआईडी पर सेट करता है. Firebase Authentication, सुरक्षा के नियमों में request.auth वैरिएबल को भी पॉप्युलेट करता है.

यहां दिए गए सुरक्षा नियम में, request.auth और resource.data वैरिएबल का इस्तेमाल किया गया है. इससे हर story के लिए, पढ़ने और लिखने का ऐक्सेस सिर्फ़ उसके लेखक को मिलता है:

service cloud.firestore {
  match /databases/{database}/documents {
    match /stories/{storyid} {
      // Only the authenticated user who authored the document can read or write
      allow read, write: if request.auth != null && request.auth.uid == resource.data.author;
    }
  }
}

मान लें कि आपके ऐप्लिकेशन में एक ऐसा पेज है जो उपयोगकर्ता को उन दस्तावेज़ों की सूची दिखाता है जो उसने बनाए हैं.story इस पेज को भरने के लिए, इस क्वेरी का इस्तेमाल किया जा सकता है. हालांकि, यह क्वेरी काम नहीं करेगी, क्योंकि इसमें सुरक्षा के नियमों जैसी पाबंदियां शामिल नहीं हैं:

अमान्य: क्वेरी की पाबंदियां, सुरक्षा नियमों की पाबंदियों से मेल नहीं खातीं

// This query will fail
db.collection("stories").get()

क्वेरी तब भी काम नहीं करती, जब मौजूदा उपयोगकर्ता ही हर story दस्तावेज़ का लेखक हो. इसकी वजह यह है कि जब Rules आपके सुरक्षा नियमों को लागू करता है, तो वह क्वेरी का आकलन उसके संभावित नतीजे के सेट के आधार पर करता है, न कि आपके डेटाबेस में मौजूद दस्तावेज़ों की असल प्रॉपर्टी के आधार पर. अगर किसी क्वेरी में संभावित तौर पर ऐसे दस्तावेज़ शामिल हो सकते हैं जो सुरक्षा से जुड़े आपके नियमों का उल्लंघन करते हैं, तो क्वेरी पूरी नहीं होगी.

इसके उलट, यह क्वेरी सफल होती है, क्योंकि इसमें author फ़ील्ड पर वही पाबंदी शामिल है जो सुरक्षा नियमों में है:

मान्य: क्वेरी की पाबंदियां, सुरक्षा नियमों की पाबंदियों से मेल खाती हैं

var user = firebase.auth().currentUser;

db.collection("stories").where("author", "==", user.uid).get()

किसी फ़ील्ड के आधार पर दस्तावेज़ों को सुरक्षित करना और क्वेरी करना

क्वेरी और नियमों के बीच इंटरैक्शन को बेहतर तरीके से दिखाने के लिए, यहां दिए गए सुरक्षा नियम stories कलेक्शन के लिए, पढ़ने का ऐक्सेस बढ़ाते हैं. इससे कोई भी उपयोगकर्ता उन story दस्तावेज़ों को पढ़ सकता है जिनमें published फ़ील्ड को true पर सेट किया गया है.

service cloud.firestore {
  match /databases/{database}/documents {
    match /stories/{storyid} {
      // Anyone can read a published story; only story authors can read unpublished stories
      allow read: if resource.data.published == true || (request.auth != null && request.auth.uid == resource.data.author);
      // Only story authors can write
      allow write: if request.auth != null && request.auth.uid == resource.data.author;
    }
  }
}

पब्लिश किए गए पेजों की क्वेरी में, सुरक्षा के नियमों जैसी ही पाबंदियां शामिल होनी चाहिए:

db.collection("stories").where("published", "==", true).get()

क्वेरी की शर्त .where("published", "==", true) यह गारंटी देती है कि किसी भी नतीजे के लिए, resource.data.published की वैल्यू true है. इसलिए, यह क्वेरी सुरक्षा के नियमों का पालन करती है और इसे डेटा को ऐक्सेस करने की अनुमति है.

OR क्वेरी

किसी नियम के सेट के लिए लॉजिकल OR क्वेरी (or, in या array-contains-any) का आकलन करते समय, नियम हर तुलना वैल्यू का अलग-अलग आकलन करते हैं. हर तुलना वैल्यू को सुरक्षा नियम की पाबंदियों को पूरा करना होगा. उदाहरण के लिए, इस नियम के लिए:

match /mydocuments/{doc} {
  allow read: if resource.data.x > 5;
}

अमान्य: क्वेरी से यह गारंटी नहीं मिलती कि सभी संभावित दस्तावेज़ों के लिए x > 5

// These queries will fail
query(db.collection("mydocuments"),
      or(where("x", "==", 1),
         where("x", "==", 6)
      )
    )

query(db.collection("mydocuments"),
      where("x", "in", [1, 3, 6, 42, 99])
    )

मान्य: क्वेरी यह गारंटी देती है कि सभी संभावित दस्तावेज़ों के लिए x > 5

query(db.collection("mydocuments"),
      or(where("x", "==", 6),
         where("x", "==", 42)
      )
    )

query(db.collection("mydocuments"),
      where("x", "in", [6, 42, 99, 105, 200])
    )

क्वेरी पर लागू होने वाली पाबंदियों का आकलन करना

आपके सुरक्षा नियम, अपनी पाबंदियों के आधार पर क्वेरी को स्वीकार या अस्वीकार भी कर सकते हैं. request.query वैरिएबल में, क्वेरी की limit, offset, और orderBy प्रॉपर्टी शामिल होती हैं. उदाहरण के लिए, आपके सुरक्षा नियम ऐसी किसी भी क्वेरी को अस्वीकार कर सकते हैं जो किसी खास रेंज में वापस लाए गए दस्तावेज़ों की ज़्यादा से ज़्यादा संख्या को सीमित नहीं करती:

allow list: if request.query.limit <= 10;

यहां दिए गए नियमों के सेट से पता चलता है कि सुरक्षा के नियम कैसे लिखे जाते हैं. ये नियम, क्वेरी पर लगाई गई पाबंदियों का आकलन करते हैं. इस उदाहरण में, पिछले stories नियमों के सेट को इन बदलावों के साथ बड़ा किया गया है:

  • नियमों का सेट, पढ़ने के नियम को get और list के नियमों में अलग करता है.
  • get नियम के तहत, सिर्फ़ सार्वजनिक दस्तावेज़ों या उपयोगकर्ता के बनाए गए दस्तावेज़ों को ही वापस लाया जा सकता है.
  • list नियम, get की तरह ही पाबंदियां लागू करता है. हालांकि, यह क्वेरी के लिए होता है. यह क्वेरी की सीमा भी जांचता है. इसके बाद, बिना सीमा वाली या 10 से ज़्यादा सीमा वाली किसी भी क्वेरी को अस्वीकार कर देता है.
  • नियमों का सेट, कोड के डुप्लीकेट होने से बचने के लिए authorOrPublished() फ़ंक्शन तय करता है.
service cloud.firestore {

  match /databases/{database}/documents {

    match /stories/{storyid} {

      // Returns `true` if the requested story is 'published'
      // or the user authored the story
      function authorOrPublished() {
        return resource.data.published == true || request.auth.uid == resource.data.author;
      }

      // Deny any query not limited to 10 or fewer documents
      // Anyone can query published stories
      // Authors can query their unpublished stories
      allow list: if request.query.limit <= 10 &&
                     authorOrPublished();

      // Anyone can retrieve a published story
      // Only a story's author can retrieve an unpublished story
      allow get: if authorOrPublished();

      // Only a story's author can write to a story
      allow write: if request.auth.uid == resource.data.author;
    }

  }
}

कलेक्शन ग्रुप क्वेरी और सुरक्षा के नियम

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

कलेक्शन ग्रुप के आधार पर दस्तावेज़ों को सुरक्षित करना और क्वेरी करना

आपको अपने सुरक्षा नियमों में, कलेक्शन ग्रुप के लिए नियम लिखकर, कलेक्शन ग्रुप की क्वेरी को साफ़ तौर पर अनुमति देनी होगी:

  1. पक्का करें कि rules_version = '2'; आपके नियमों के सेट की पहली लाइन हो. कलेक्शन ग्रुप क्वेरी के लिए, सुरक्षा नियमों के वर्शन 2 के नए रिकर्सिव वाइल्डकार्ड {name=**} व्यवहार की ज़रूरत होती है.
  2. match /{path=**}/[COLLECTION_ID]/{doc} का इस्तेमाल करके, अपने कलेक्शन ग्रुप के लिए कोई नियम लिखें.

उदाहरण के लिए, मान लें कि किसी फ़ोरम को forum दस्तावेज़ों में व्यवस्थित किया गया है. इनमें posts सब-कलेक्शन शामिल हैं:

/forums/{forumid}/posts/{postid}

{
  author: "some_auth_id",
  authorname: "some_username",
  content: "I just read a great story.",
}

इस ऐप्लिकेशन में, हम पोस्ट को उनके मालिकों के लिए बदलाव करने लायक और पुष्टि किए गए उपयोगकर्ताओं के लिए पढ़ने लायक बनाते हैं:

service cloud.firestore {
  match /databases/{database}/documents {
    match /forums/{forumid}/posts/{post} {
      // Only authenticated users can read
      allow read: if request.auth != null;
      // Only the post author can write
      allow write: if request.auth != null && request.auth.uid == resource.data.author;
    }
  }
}

पुष्टि किया गया कोई भी उपयोगकर्ता, किसी एक फ़ोरम की पोस्ट वापस पा सकता है:

db.collection("forums/technology/posts").get()

अगर आपको मौजूदा उपयोगकर्ता को सभी फ़ोरम में उसकी पोस्ट दिखानी हैं, तो क्या करना होगा? सभी posts कलेक्शन से नतीजे पाने के लिए, कलेक्शन ग्रुप क्वेरी का इस्तेमाल किया जा सकता है:

var user = firebase.auth().currentUser;

db.collectionGroup("posts").where("author", "==", user.uid).get()

आपको सुरक्षा के नियमों में, इस क्वेरी को अनुमति देनी होगी. इसके लिए, posts कलेक्शन ग्रुप के लिए, पढ़ने या सूची बनाने का नियम लिखें:

rules_version = '2';
service cloud.firestore {

  match /databases/{database}/documents {
    // Authenticated users can query the posts collection group
    // Applies to collection queries, collection group queries, and
    // single document retrievals
    match /{path=**}/posts/{post} {
      allow read: if request.auth != null;
    }
    match /forums/{forumid}/posts/{postid} {
      // Only a post's author can write to a post
      allow write: if request.auth != null && request.auth.uid == resource.data.author;

    }
  }
}

हालांकि, ध्यान दें कि ये नियम, आईडी posts वाले सभी कलेक्शन पर लागू होंगे. इससे कोई फ़र्क़ नहीं पड़ता कि वे किस क्रम में हैं. उदाहरण के लिए, ये नियम इन सभी posts कलेक्शन पर लागू होते हैं:

  • /posts/{postid}
  • /forums/{forumid}/posts/{postid}
  • /forums/{forumid}/subforum/{subforumid}/posts/{postid}

किसी फ़ील्ड के आधार पर, कलेक्शन ग्रुप की क्वेरी को सुरक्षित करना

सिंगल-कलेक्शन क्वेरी की तरह ही, कलेक्शन ग्रुप क्वेरी को भी सुरक्षा के नियमों के तहत तय की गई शर्तों को पूरा करना होगा. उदाहरण के लिए, हम हर फ़ोरम पोस्ट में published फ़ील्ड जोड़ सकते हैं, जैसा कि हमने ऊपर stories के उदाहरण में किया है:

/forums/{forumid}/posts/{postid}

{
  author: "some_auth_id",
  authorname: "some_username",
  content: "I just read a great story.",
  published: false
}

इसके बाद, हम published स्टेटस और पोस्ट author के आधार पर, posts कलेक्शन ग्रुप के लिए नियम लिख सकते हैं:

rules_version = '2';
service cloud.firestore {

  match /databases/{database}/documents {

    // Returns `true` if the requested post is 'published'
    // or the user authored the post
    function authorOrPublished() {
      return resource.data.published == true || request.auth.uid == resource.data.author;
    }

    match /{path=**}/posts/{post} {

      // Anyone can query published posts
      // Authors can query their unpublished posts
      allow list: if authorOrPublished();

      // Anyone can retrieve a published post
      // Authors can retrieve an unpublished post
      allow get: if authorOrPublished();
    }

    match /forums/{forumid}/posts/{postid} {
      // Only a post's author can write to a post
      allow write: if request.auth.uid == resource.data.author;
    }
  }
}

इन नियमों की मदद से, वेब, Apple, और Android क्लाइंट ये क्वेरी कर सकते हैं:

  • फ़ोरम में पब्लिश की गई पोस्ट को कोई भी व्यक्ति वापस ला सकता है:

    db.collection("forums/technology/posts").where('published', '==', true).get()
    
  • कोई भी व्यक्ति, सभी फ़ोरम पर किसी लेखक की पब्लिश की गई पोस्ट को वापस पा सकता है:

    db.collectionGroup("posts").where("author", "==", "some_auth_id").where('published', '==', true).get()
    
  • लेखक, सभी फ़ोरम पर पब्लिश की गई और पब्लिश नहीं की गई अपनी सभी पोस्ट वापस पा सकते हैं:

    var user = firebase.auth().currentUser;
    
    db.collectionGroup("posts").where("author", "==", user.uid).get()
    

कलेक्शन ग्रुप और दस्तावेज़ के पाथ के आधार पर, दस्तावेज़ों को सुरक्षित करना और क्वेरी करना

कुछ मामलों में, हो सकता है कि आप दस्तावेज़ के पाथ के आधार पर, कलेक्शन ग्रुप की क्वेरी पर पाबंदी लगाना चाहें. इन पाबंदियों को लागू करने के लिए, किसी फ़ील्ड के आधार पर दस्तावेज़ों को सुरक्षित करने और क्वेरी करने की तकनीकों का इस्तेमाल किया जा सकता है.

मान लें कि कोई ऐप्लिकेशन, कई स्टॉक और क्रिप्टो करंसी एक्सचेंज के बीच हर उपयोगकर्ता के लेन-देन को ट्रैक करता है:

/users/{userid}/exchange/{exchangeid}/transactions/{transaction}

{
  amount: 100,
  exchange: 'some_exchange_name',
  timestamp: April 1, 2019 at 12:00:00 PM UTC-7,
  user: "some_auth_id",
}

user फ़ील्ड पर ध्यान दें. हमें पता होता है कि दस्तावेज़ के पाथ से, किस उपयोगकर्ता के पास transaction दस्तावेज़ का मालिकाना हक है. इसके बावजूद, हम हर transaction दस्तावेज़ में इस जानकारी को डुप्लीकेट करते हैं. ऐसा करने से, हमें दो काम करने में मदद मिलती है:

  • कलेक्शन ग्रुप की ऐसी क्वेरी लिखें जो सिर्फ़ उन दस्तावेज़ों तक सीमित हों जिनके दस्तावेज़ पाथ में कोई खास /users/{userid} शामिल हो. उदाहरण के लिए:

    var user = firebase.auth().currentUser;
    // Return current user's last five transactions across all exchanges
    db.collectionGroup("transactions").where("user", "==", user).orderBy('timestamp').limit(5)
    
  • transactions कलेक्शन ग्रुप में मौजूद सभी क्वेरी के लिए, यह पाबंदी लागू करें, ताकि कोई उपयोगकर्ता किसी दूसरे उपयोगकर्ता के transaction दस्तावेज़ों को ऐक्सेस न कर सके.

हम सुरक्षा से जुड़े अपने नियमों में इस पाबंदी को लागू करते हैं. साथ ही, user फ़ील्ड के लिए डेटा की पुष्टि करने की सुविधा शामिल करते हैं:

rules_version = '2';
service cloud.firestore {

  match /databases/{database}/documents {

    match /{path=**}/transactions/{transaction} {
      // Authenticated users can retrieve only their own transactions
      allow read: if resource.data.user == request.auth.uid;
    }

    match /users/{userid}/exchange/{exchangeid}/transactions/{transaction} {
      // Authenticated users can write to their own transactions subcollections
      // Writes must populate the user field with the correct auth id
      allow write: if userid == request.auth.uid && request.data.user == request.auth.uid
    }
  }
}

अगले चरण