Cloud Firestore के सुरक्षा नियमों के लिए लिखने की शर्तें

यह गाइड सुरक्षा के नियम बनाने से जुड़ी गाइड पर आधारित है. इसमें यह बताया गया है कि Cloud Firestore के सुरक्षा नियमों में शर्तें कैसे जोड़ी जा सकती हैं. अगर आपको Cloud Firestore के सुरक्षा नियमों की बुनियादी बातों के बारे में नहीं पता है, तो शुरू करने का तरीका बताने वाली गाइड देखें.

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

पुष्टि करना

सुरक्षा के सबसे सामान्य नियमों में से एक है, उपयोगकर्ता की पुष्टि करने की स्थिति के आधार पर ऐक्सेस को कंट्रोल करना. उदाहरण के लिए, हो सकता है कि आपका ऐप्लिकेशन सिर्फ़ साइन-इन किए हुए उपयोगकर्ताओं को डेटा लिखने की अनुमति देना चाहे:

service cloud.firestore {
  match /databases/{database}/documents {
    // Allow the user to access documents in the "cities" collection
    // only if they are authenticated.
    match /cities/{city} {
      allow read, write: if request.auth != null;
    }
  }
}

दूसरा सामान्य पैटर्न यह पक्का करना है कि उपयोगकर्ता सिर्फ़ अपना डेटा पढ़ और लिख सकें:

service cloud.firestore {
  match /databases/{database}/documents {
    // Make sure the uid of the requesting user matches name of the user
    // document. The wildcard expression {userId} makes the userId variable
    // available in rules.
    match /users/{userId} {
      allow read, update, delete: if request.auth != null && request.auth.uid == userId;
      allow create: if request.auth != null;
    }
  }
}

अगर आपका ऐप्लिकेशन, Firebase से पुष्टि करने की सुविधा या Google Cloud Identity Platform का इस्तेमाल करता है, तो request.auth वैरिएबल में डेटा का अनुरोध करने वाले क्लाइंट की पुष्टि करने से जुड़ी जानकारी शामिल होती है. request.auth के बारे में ज़्यादा जानकारी के लिए, पहचान फ़ाइल दस्तावेज़ देखें.

डेटा सत्यापन

कई ऐप्लिकेशन, डेटाबेस में मौजूद दस्तावेज़ों पर फ़ील्ड के तौर पर ऐक्सेस कंट्रोल की जानकारी सेव करते हैं. दस्तावेज़ के डेटा के आधार पर, Cloud Firestore के सुरक्षा नियम, डाइनैमिक तौर पर ऐक्सेस की अनुमति दे सकते हैं या अस्वीकार कर सकते हैं:

service cloud.firestore {
  match /databases/{database}/documents {
    // Allow the user to read data if the document has the 'visibility'
    // field set to 'public'
    match /cities/{city} {
      allow read: if resource.data.visibility == 'public';
    }
  }
}

resource वैरिएबल, अनुरोध किए गए दस्तावेज़ के बारे में बताता है. साथ ही, resource.data, दस्तावेज़ में सेव किए गए सभी फ़ील्ड और वैल्यू का मैप है. resource वैरिएबल के बारे में ज़्यादा जानकारी के लिए, रेफ़रंस दस्तावेज़ देखें.

डेटा लिखते समय, हो सकता है कि आप आने वाले डेटा की तुलना मौजूदा डेटा से करना चाहें. इस मामले में, अगर आपके नियमसेट में लिखने की मंज़ूरी बाकी है, तो request.resource वैरिएबल में दस्तावेज़ की आने वाली स्थिति शामिल होगी. सिर्फ़ दस्तावेज़ फ़ील्ड के सबसेट में बदलाव करने वाली update कार्रवाइयों के लिए, request.resource वैरिएबल में कार्रवाई के बाद दस्तावेज़ की 'मंज़ूरी बाकी है' स्थिति शामिल होगी. अनचाहे या अलग-अलग डेटा अपडेट को रोकने के लिए, request.resource में फ़ील्ड की वैल्यू देखें:

service cloud.firestore {
  match /databases/{database}/documents {
    // Make sure all cities have a positive population and
    // the name is not changed
    match /cities/{city} {
      allow update: if request.resource.data.population > 0
                    && request.resource.data.name == resource.data.name;
    }
  }
}

अन्य दस्तावेज़ों को ऐक्सेस करना

get() और exists() फ़ंक्शन का इस्तेमाल करके, आपके सुरक्षा नियम डेटाबेस के दूसरे दस्तावेज़ों के आधार पर, आने वाले अनुरोधों की जांच कर सकते हैं. get() और exists(), दोनों फ़ंक्शन में दस्तावेज़ के पूरी तरह से बताए गए पाथ शामिल किए जाने चाहिए. get() और exists() के लिए पाथ बनाने के लिए, वैरिएबल का इस्तेमाल करते समय, आपको $(variable) सिंटैक्स का इस्तेमाल करके वैरिएबल को साफ़ तौर पर एस्केप करना होगा.

नीचे दिए गए उदाहरण में, database वैरिएबल को मैच स्टेटमेंट match /databases/{database}/documents से कैप्चर किया गया है. इसका इस्तेमाल पाथ बनाने के लिए किया गया है:

service cloud.firestore {
  match /databases/{database}/documents {
    match /cities/{city} {
      // Make sure a 'users' document exists for the requesting user before
      // allowing any writes to the 'cities' collection
      allow create: if request.auth != null && exists(/databases/$(database)/documents/users/$(request.auth.uid));

      // Allow the user to delete cities if their user document has the
      // 'admin' field set to 'true'
      allow delete: if request.auth != null && get(/databases/$(database)/documents/users/$(request.auth.uid)).data.admin == true;
    }
  }
}

लिखने के लिए, आप किसी लेन-देन या लेख के बैच के पूरा होने के बाद, लेन-देन या बैच के भेजे जाने से पहले किसी दस्तावेज़ की स्थिति ऐक्सेस करने के लिए getAfter() फ़ंक्शन का इस्तेमाल कर सकते हैं. get() की तरह, getAfter() फ़ंक्शन पूरी तरह से बताया गया दस्तावेज़ का पाथ लेता है. getAfter() का इस्तेमाल करके राइट के ऐसे सेट तय किए जा सकते हैं जो ट्रांज़ैक्शन या बैच के तौर पर एक साथ होते हैं.

कॉल की सीमाएं ऐक्सेस करना

हर नियम सेट का आकलन करने के लिए, दस्तावेज़ को ऐक्सेस करने के लिए एक सीमा तय की गई है:

  • एक दस्तावेज़ वाले अनुरोधों और क्वेरी के अनुरोधों के लिए 10.
  • एक से ज़्यादा दस्तावेज़ों को पढ़ने, लेन-देन, और बैच में लिखने के लिए 20. 10 की पिछली सीमा हर कार्रवाई पर भी लागू होती है.

    उदाहरण के लिए, मान लें कि आपने लिखने के लिए तीन कार्रवाइयों के साथ, एक साथ कई अनुरोध भेजने का अनुरोध किया है. साथ ही, आपके सुरक्षा नियम, हर बदलाव की पुष्टि करने के लिए, दस्तावेज़ को ऐक्सेस करने के दो कॉल का इस्तेमाल करते हैं. इस मामले में, हर एडिट के लिए, 10 में से 2 ऐक्सेस कॉल का इस्तेमाल किया जाता है. साथ ही, एक बैच में लिखने के अनुरोध के लिए, 20 में से 6 ऐक्सेस कॉल का इस्तेमाल किया जाता है.

सीमा से ज़्यादा नतीजे पाने पर, अनुमति नहीं मिलने की गड़बड़ी दिखेगी. कुछ दस्तावेज़ ऐक्सेस कॉल कैश मेमोरी में सेव किए जा सकते हैं और कैश मेमोरी में सेव किए गए कॉल, इन सीमाओं में नहीं गिने जाते हैं.

इन सीमाओं से लेन-देन और बैच राइट पर कैसे असर पड़ता है, इस बारे में ज़्यादा जानने के लिए ऐटॉमिक ऑपरेशन सुरक्षित करने से जुड़ी गाइड देखें.

कॉल और मूल्य-निर्धारण ऐक्सेस करें

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

कस्टम फ़ंक्शन

जैसे-जैसे आपके सुरक्षा नियम ज़्यादा जटिल होते जाते हैं, वैसे-वैसे आप शर्तों के सेट को फ़ंक्शन में रैप कर सकते हैं, जिनका आप अपने नियमसेट में फिर से इस्तेमाल कर सकते हैं. सुरक्षा नियमों में कस्टम फ़ंक्शन इस्तेमाल किए जा सकते हैं. कस्टम फ़ंक्शन का सिंटैक्स कुछ-कुछ JavaScript जैसा है, लेकिन सुरक्षा नियम के फ़ंक्शन डोमेन के हिसाब से खास भाषा में लिखे गए हैं जिसमें कुछ अहम सीमाएं हैं:

  • फ़ंक्शन में सिर्फ़ एक return स्टेटमेंट हो सकता है. इनमें कोई खास तर्क नहीं हो सकता. उदाहरण के लिए, वे लूप नहीं चला सकते या बाहरी सेवाओं को कॉल नहीं कर सकते.
  • फ़ंक्शन, उस स्कोप से अपने-आप फ़ंक्शन और वैरिएबल को ऐक्सेस कर सकते हैं जिसमें उन्हें तय किया गया है. उदाहरण के लिए, service cloud.firestore स्कोप में तय किए गए किसी फ़ंक्शन के पास resource वैरिएबल और get() और exists() जैसे बिल्ट-इन फ़ंक्शन का ऐक्सेस होता है.
  • फ़ंक्शन दूसरे फ़ंक्शन को कॉल कर सकते हैं, लेकिन हो सकता है कि वे बार-बार न हों. कॉल स्टैक की कुल डेप्थ 10 है.
  • नियमों के वर्शन v2 में, फ़ंक्शन let कीवर्ड का इस्तेमाल करके वैरिएबल तय कर सकते हैं. फ़ंक्शन में ज़्यादा से ज़्यादा 10 लेट बाइंडिंग हो सकती हैं, लेकिन उनके आखिर में रिटर्न स्टेटमेंट होना चाहिए.

फ़ंक्शन को function कीवर्ड से तय किया जाता है और इसके लिए शून्य या उससे ज़्यादा आर्ग्युमेंट इस्तेमाल किए जाते हैं. उदाहरण के लिए, हो सकता है कि आप ऊपर दिए गए उदाहरणों में इस्तेमाल की गई दो तरह की शर्तों को एक ही फ़ंक्शन में मिलाना चाहें:

service cloud.firestore {
  match /databases/{database}/documents {
    // True if the user is signed in or the requested data is 'public'
    function signedInOrPublic() {
      return request.auth.uid != null || resource.data.visibility == 'public';
    }

    match /cities/{city} {
      allow read, write: if signedInOrPublic();
    }

    match /users/{user} {
      allow read, write: if signedInOrPublic();
    }
  }
}

सुरक्षा के नियमों में फ़ंक्शन का इस्तेमाल करने से, उन्हें बनाए रखने में मदद मिलती है. ऐसा इसलिए, क्योंकि आपके नियमों की जटिलता बढ़ती जा रही है.

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

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

उदाहरण के लिए, सुरक्षा के इस नियम को अपनाएं:

service cloud.firestore {
  match /databases/{database}/documents {
    // Allow the user to read data if the document has the 'visibility'
    // field set to 'public'
    match /cities/{city} {
      allow read: if resource.data.visibility == 'public';
    }
  }
}

अस्वीकार किया गया: यह नियम नीचे दी गई क्वेरी को अस्वीकार कर देता है, क्योंकि नतीजे के सेट में ऐसे दस्तावेज़ शामिल हो सकते हैं जिनमें visibility, public न हो:

वेब
db.collection("cities").get()
    .then(function(querySnapshot) {
        querySnapshot.forEach(function(doc) {
            console.log(doc.id, " => ", doc.data());
    });
});

अनुमति है: यह नियम इस क्वेरी की अनुमति देता है, क्योंकि where("visibility", "==", "public") क्लॉज़ गारंटी देते हैं कि नतीजा सेट नियम की शर्त पूरी करता है:

वेब
db.collection("cities").where("visibility", "==", "public").get()
    .then(function(querySnapshot) {
        querySnapshot.forEach(function(doc) {
            console.log(doc.id, " => ", doc.data());
        });
    });

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

अगले चरण