सुरक्षित रूप से क्वेरी डेटा

यह पृष्ठ सुरक्षा नियमों की संरचना और सुरक्षा नियमों के लिए लेखन शर्तों की अवधारणाओं पर आधारित है ताकि यह समझाया जा सके कि क्लाउड फायरस्टोर सुरक्षा नियम प्रश्नों के साथ कैसे इंटरैक्ट करते हैं। यह इस बात पर करीब से नज़र डालता है कि सुरक्षा नियम आपके द्वारा लिखे जा सकने वाले प्रश्नों को कैसे प्रभावित करते हैं और यह वर्णन करता है कि यह कैसे सुनिश्चित किया जाए कि आपके प्रश्न आपके सुरक्षा नियमों के समान बाधाओं का उपयोग करें। यह पृष्ठ यह भी बताता है कि limit और orderBy जैसे क्वेरी गुणों के आधार पर प्रश्नों को अनुमति देने या अस्वीकार करने के लिए सुरक्षा नियम कैसे लिखें।

नियम फ़िल्टर नहीं हैं

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

प्रश्न और सुरक्षा नियम

जैसा कि नीचे दिए गए उदाहरणों से पता चलता है, आपको अपने प्रश्नों को अपने सुरक्षा नियमों की सीमाओं के अनुरूप लिखना होगा।

auth.uid पर आधारित दस्तावेज़ों को सुरक्षित और क्वेरी करें

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

/कहानियां/{कहानीआईडी}

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

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

निम्नलिखित सुरक्षा नियम प्रत्येक story को उसके लेखक तक पढ़ने और लिखने की पहुंच को प्रतिबंधित करने के लिए request.auth और resource.data चर का उपयोग करता है:

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

इसके विपरीत, निम्नलिखित क्वेरी सफल होती है, क्योंकि इसमें 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} उपयोग करके अपने संग्रह समूह के लिए एक नियम लिखें।

उदाहरण के लिए, posts उपसंग्रह वाले forum दस्तावेज़ों में व्यवस्थित फ़ोरम पर विचार करें:

/फ़ोरम/{फ़ोरमिड}/पोस्ट/{पोस्टिड}

{
  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 उदाहरण में किया था:

/फ़ोरम/{फ़ोरमिड}/पोस्ट/{पोस्टिड}

{
  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;
    }
  }
}

इन नियमों के साथ, वेब, ऐप्पल और एंड्रॉइड क्लाइंट निम्नलिखित प्रश्न पूछ सकते हैं:

  • कोई भी व्यक्ति फोरम में प्रकाशित पोस्ट पुनः प्राप्त कर सकता है:

    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()
    

संग्रह समूह और दस्तावेज़ पथ के आधार पर दस्तावेज़ों को सुरक्षित और क्वेरी करें

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

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

/उपयोगकर्ता/{उपयोगकर्ता आईडी}/एक्सचेंज/{एक्सचेंजआईडी}/लेनदेन/{लेनदेन}

{
  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
    }
  }
}

अगले कदम