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

इस गाइड में, सुरक्षा के नियमों को स्ट्रक्चर करना गाइड में दी गई जानकारी को आगे बढ़ाया गया है. इसमें बताया गया है कि Cloud Firestore Security Rules में शर्तें कैसे जोड़ी जाती हैं. अगर आपको Cloud Firestore Security Rules की बुनियादी बातों के बारे में नहीं पता है, तो शुरू करने से जुड़ी गाइड देखें.

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

पुष्टि करना

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

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 Authentication या Google Cloud Identity Platform का इस्तेमाल करता है, तो request.auth वैरिएबल में, डेटा का अनुरोध करने वाले क्लाइंट की पुष्टि करने से जुड़ी जानकारी होती है. request.auth के बारे में ज़्यादा जानकारी के लिए, रेफ़रंस दस्तावेज़ देखें.

डेटा सत्यापन

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

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 let बाइंडिंग हो सकती हैं. हालांकि, यह ज़रूरी है कि फ़ंक्शन, return स्टेटमेंट के साथ खत्म हो.

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

अगले चरण