रीयलटाइम डेटाबेस के सुरक्षा नियमों की भाषा का मुख्य सिंटैक्स जानें

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

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

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

सुरक्षा के नियमों को व्यवस्थित करना

रीयलटाइम डेटाबेस के सुरक्षा नियम, JSON दस्तावेज़ में मौजूद JavaScript जैसे एक्सप्रेशन से बने होते हैं. आपके नियमों का स्ट्रक्चर, आपके डेटाबेस में सेव किए गए डेटा के स्ट्रक्चर के मुताबिक होना चाहिए.

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

उदाहरण के लिए, अगर हमें parent_node के तहत child_node को सुरक्षित करना है, तो इस्तेमाल किया जाने वाला सामान्य सिंटैक्स यह है:

{
  "rules": {
    "parent_node": {
      "child_node": {
        ".read": <condition>,
        ".write": <condition>,
        ".validate": <condition>,
      }
    }
  }
}

आइए, इस पैटर्न को लागू करते हैं. उदाहरण के लिए, मान लें कि आप मैसेज की सूची का ट्रैक रख रहे हैं और आपके पास ऐसा डेटा है:

{
  "messages": {
    "message0": {
      "content": "Hello",
      "timestamp": 1405704370369
    },
    "message1": {
      "content": "Goodbye",
      "timestamp": 1405704395231
    },
    ...
  }
}

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

{
  "rules": {
    // For requests to access the 'messages' node...
    "messages": {
      // ...and the individual wildcarded 'message' nodes beneath
      // (we'll cover wildcarding variables more a bit later)....
      "$message": {

        // For each message, allow a read operation if <condition>. In this
        // case, we specify our condition as "true", so read access is always granted.
        ".read": "true",

        // For read-only behavior, we specify that for write operations, our
        // condition is false.
        ".write": "false"
      }
    }
  }
}

बुनियादी नियमों के ऑपरेशन

डेटा पर किए जा रहे ऑपरेशन के टाइप के आधार पर, सुरक्षा लागू करने के लिए तीन तरह के नियम होते हैं: .write, .read, और .validate. यहां उनके मकसद के बारे में खास जानकारी दी गई है:

नियम के टाइप
.read इससे यह पता चलता है कि उपयोगकर्ता, डेटा को कब पढ़ सकते हैं.
.write इससे पता चलता है कि डेटा को कब और कहां सेव किया जा सकता है.
.validate इससे पता चलता है कि सही तरीके से फ़ॉर्मैट की गई वैल्यू कैसी दिखेगी, उसमें चाइल्ड एट्रिब्यूट और डेटा टाइप शामिल है या नहीं.

वाइल्डकार्ड कैप्चर वैरिएबल

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

{
  "rules": {
    "rooms": {
      // this rule applies to any child of /rooms/, the key for each room id
      // is stored inside $room_id variable for reference
      "$room_id": {
        "topic": {
          // the room's topic can be changed if the room id has "public" in it
          ".write": "$room_id.contains('public')"
        }
      }
    }
  }
}

डाइनैमिक $ वैरिएबल का इस्तेमाल, पाथ के स्थिर नामों के साथ भी किया जा सकता है. इस उदाहरण में, हम $other वैरिएबल का इस्तेमाल करके, .validate नियम तय कर रहे हैं. इससे यह पक्का होता है कि widget में title और color के अलावा कोई और चाइल्ड एलिमेंट न हो. अगर किसी भी तरह के बदलाव से अतिरिक्त चाइल्ड ऑब्जेक्ट बनते हैं, तो वह बदलाव लागू नहीं होगा.

{
  "rules": {
    "widget": {
      // a widget can have a title or color attribute
      "title": { ".validate": true },
      "color": { ".validate": true },

      // but no other child paths are allowed
      // in this case, $other means any key excluding "title" and "color"
      "$other": { ".validate": false }
    }
  }
}

नियम पढ़ें और लिखें कैस्केड

.read और .write नियम, ऊपर से नीचे की ओर काम करते हैं. इसमें, कम प्राथमिकता वाले नियम, ज़्यादा प्राथमिकता वाले नियमों को बदल देते हैं. अगर कोई नियम किसी खास पाथ पर पढ़ने या लिखने की अनुमतियां देता है, तो वह उसके नीचे मौजूद सभी चाइल्ड नोड का ऐक्सेस भी देता है. इस स्ट्रक्चर का इस्तेमाल करें:

{
  "rules": {
     "foo": {
        // allows read to /foo/*
        ".read": "data.child('baz').val() === true",
        "bar": {
          /* ignored, since read was allowed already */
          ".read": false
        }
     }
  }
}

सुरक्षा के इस स्ट्रक्चर की मदद से, /bar/ को तब पढ़ा जा सकता है, जब /foo/ में वैल्यू true वाला चाइल्ड baz शामिल हो. /foo/bar/ में दिए गए ".read": false नियम का यहां कोई असर नहीं पड़ता, क्योंकि चाइल्ड पाथ से ऐक्सेस रद्द नहीं किया जा सकता.

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

ध्यान दें कि .validate नियम कैस्केड नहीं होते. डेटा डालने की अनुमति देने के लिए, पुष्टि करने वाले सभी नियमों को हैरारकी के सभी लेवल पर पूरा करना ज़रूरी है.

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

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

{
  "rules": {
    "records": {
      "rec1": {
        ".read": true
      },
      "rec2": {
        ".read": false
      }
    }
  }
}

यह समझे बिना कि नियमों का आकलन एक-एक करके किया जाता है, ऐसा लग सकता है कि /records/ पाथ को फ़ेच करने पर rec1 दिखेगा, लेकिन rec2 नहीं. हालांकि, असल नतीजा गड़बड़ी है:

JavaScript
var db = firebase.database();
db.ref("records").once("value", function(snap) {
  // success method is not called
}, function(err) {
  // error callback triggered with PERMISSION_DENIED
});
Objective-C
ध्यान दें: Firebase का यह प्रॉडक्ट, ऐप्लिकेशन क्लिप टारगेट पर उपलब्ध नहीं है.
FIRDatabaseReference *ref = [[FIRDatabase database] reference];
[[_ref child:@"records"] observeSingleEventOfType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  // success block is not called
} withCancelBlock:^(NSError * _Nonnull error) {
  // cancel block triggered with PERMISSION_DENIED
}];
Swift
ध्यान दें: Firebase का यह प्रॉडक्ट, ऐप्लिकेशन क्लिप टारगेट पर उपलब्ध नहीं है.
var ref = FIRDatabase.database().reference()
ref.child("records").observeSingleEventOfType(.Value, withBlock: { snapshot in
    // success block is not called
}, withCancelBlock: { error in
    // cancel block triggered with PERMISSION_DENIED
})
Java
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference ref = database.getReference("records");
ref.addListenerForSingleValueEvent(new ValueEventListener() {
  @Override
  public void onDataChange(DataSnapshot snapshot) {
    // success method is not called
  }

  @Override
  public void onCancelled(FirebaseError firebaseError) {
    // error callback triggered with PERMISSION_DENIED
  });
});
REST
curl https://docs-examples.firebaseio.com/rest/records/
# response returns a PERMISSION_DENIED error

/records/ में, डेटा को एक साथ पढ़ने की सुविधा उपलब्ध है. साथ ही, /records/ में मौजूद सभी डेटा को ऐक्सेस करने का कोई ऐसा नियम नहीं है जो डेटा पढ़ने की अनुमति देता हो. इसलिए, इससे PERMISSION_DENIED गड़बड़ी का मैसेज दिखेगा. अगर हम Firebase Console में सुरक्षा सिम्युलेटर में इस नियम का आकलन करते हैं, तो हम देख सकते हैं कि पढ़ने की अनुमति नहीं दी गई थी, क्योंकि पढ़ने से जुड़े किसी भी नियम ने /records/ पाथ को ऐक्सेस करने की अनुमति नहीं दी थी. हालांकि, ध्यान दें कि rec1 के लिए बने नियम का कभी आकलन नहीं किया गया, क्योंकि वह उस पाथ में नहीं था जिसके लिए हमने अनुरोध किया था. rec1 को फ़ेच करने के लिए, हमें इसे सीधे ऐक्सेस करना होगा:

JavaScript
var db = firebase.database();
db.ref("records/rec1").once("value", function(snap) {
  // SUCCESS!
}, function(err) {
  // error callback is not called
});
Objective-C
ध्यान दें: Firebase का यह प्रॉडक्ट, ऐप्लिकेशन क्लिप टारगेट पर उपलब्ध नहीं है.
FIRDatabaseReference *ref = [[FIRDatabase database] reference];
[[ref child:@"records/rec1"] observeSingleEventOfType:FEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
    // SUCCESS!
}];
Swift
ध्यान दें: Firebase का यह प्रॉडक्ट, ऐप्लिकेशन क्लिप टारगेट पर उपलब्ध नहीं है.
var ref = FIRDatabase.database().reference()
ref.child("records/rec1").observeSingleEventOfType(.Value, withBlock: { snapshot in
    // SUCCESS!
})
Java
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference ref = database.getReference("records/rec1");
ref.addListenerForSingleValueEvent(new ValueEventListener() {
  @Override
  public void onDataChange(DataSnapshot snapshot) {
    // SUCCESS!
  }

  @Override
  public void onCancelled(FirebaseError firebaseError) {
    // error callback is not called
  }
});
REST
curl https://docs-examples.firebaseio.com/rest/records/rec1
# SUCCESS!

ओवरलैप होने वाले स्टेटमेंट

किसी नोड पर एक से ज़्यादा नियम लागू हो सकते हैं. अगर एक से ज़्यादा नियमों के एक्सप्रेशन किसी नोड की पहचान करते हैं, तो ऐक्सेस करने के तरीके को तब अनुमति नहीं दी जाती, जब कोई भी शर्त false हो:

{
  "rules": {
    "messages": {
      // A rule expression that applies to all nodes in the 'messages' node
      "$message": {
        ".read": "true",
        ".write": "true"
      },
      // A second rule expression applying specifically to the 'message1` node
      "message1": {
        ".read": "false",
        ".write": "false"
      }
    }
  }
}

ऊपर दिए गए उदाहरण में, message1 नोड को पढ़ने की अनुमति नहीं दी जाएगी, क्योंकि दूसरा नियम हमेशा false होता है. भले ही, पहला नियम हमेशा true हो.

अगले चरण

Firebase रीयल टाइम डेटाबेस के सुरक्षा नियमों को बेहतर तरीके से समझा जा सकता है:

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

  • सुरक्षा से जुड़े सामान्य इस्तेमाल के उदाहरणों और Firebase के सुरक्षा नियमों की परिभाषाओं को देखें, जो इन समस्याओं को हल करते हैं.