এই নির্দেশিকাটি সিকিউরিটি রুলস কাঠামোবদ্ধ করার নির্দেশিকার উপর ভিত্তি করে আপনার 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 ভেরিয়েবল সম্পর্কে আরও তথ্যের জন্য, রেফারেন্স ডকুমেন্টেশন দেখুন।
ডেটা লেখার সময়, আপনি আগত ডেটার সাথে বিদ্যমান ডেটা তুলনা করতে চাইতে পারেন। এক্ষেত্রে, যদি আপনার রুলসেট পেন্ডিং রাইট (pending write) অনুমোদন করে, তাহলে 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) সিনট্যাক্স ব্যবহার করে ভেরিয়েবলগুলোকে স্পষ্টভাবে এস্কেপ করতে হবে।
নীচের উদাহরণে, match /databases/{database}/documents ম্যাচ স্টেটমেন্টের মাধ্যমে database ভেরিয়েবলটি ক্যাপচার করা হয়েছে এবং পাথটি তৈরি করতে ব্যবহৃত হয়েছে:
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() ব্যবহার করে এমন কিছু রাইটের সেট নির্ধারণ করতে পারেন, যেগুলো একটি ট্রানজ্যাকশন বা ব্যাচ হিসেবে একসাথে সম্পন্ন হতে হবে।
কল অ্যাক্সেসের সীমাবদ্ধতা
প্রতিটি নিয়ম সেট মূল্যায়নের জন্য নথি অ্যাক্সেস কলের একটি সীমা রয়েছে:
- একক-ডকুমেন্ট অনুরোধ এবং কোয়েরি অনুরোধের জন্য ১০।
একাধিক ডকুমেন্ট রিড, ট্রানজ্যাকশন এবং ব্যাচড রাইটের জন্য ২০। পূর্ববর্তী ১০-এর সীমাটি প্রতিটি অপারেশনের ক্ষেত্রেও প্রযোজ্য।
উদাহরণস্বরূপ, ধরুন আপনি ৩টি রাইট অপারেশন সহ একটি ব্যাচড রাইট রিকোয়েস্ট তৈরি করেছেন এবং আপনার সিকিউরিটি রুলগুলো প্রতিটি রাইট ভ্যালিডেট করতে ২টি ডকুমেন্ট অ্যাক্সেস কল ব্যবহার করে। এই ক্ষেত্রে, প্রতিটি রাইট তার ১০টি অ্যাক্সেস কলের মধ্যে ২টি ব্যবহার করে এবং ব্যাচড রাইট রিকোয়েস্টটি তার ২০টি অ্যাক্সেস কলের মধ্যে ৬টি ব্যবহার করে।
যেকোনো একটি সীমা অতিক্রম করলে 'অনুমতি নেই' ত্রুটি দেখা দেয়। কিছু ডকুমেন্ট অ্যাক্সেস কল ক্যাশ করা হতে পারে, এবং ক্যাশ করা কলগুলো সীমার মধ্যে গণনা করা হয় না।
এই সীমাগুলো কীভাবে ট্রানজ্যাকশন এবং ব্যাচড রাইটকে প্রভাবিত করে, তার বিস্তারিত ব্যাখ্যার জন্য অ্যাটমিক অপারেশন সুরক্ষিত করার নির্দেশিকাটি দেখুন।
কল এবং মূল্য অ্যাক্সেস করুন
এই ফাংশনগুলি ব্যবহার করলে আপনার ডাটাবেসে একটি রিড অপারেশন সম্পাদিত হয়, যার অর্থ হলো আপনার নিয়ম অনুরোধটি প্রত্যাখ্যান করলেও ডকুমেন্ট পড়ার জন্য আপনাকে বিল করা হবে। আরও নির্দিষ্ট বিলিং তথ্যের জন্য Cloud Firestore প্রাইসিং দেখুন।
কাস্টম ফাংশন
আপনার নিরাপত্তা নিয়মগুলো আরও জটিল হয়ে উঠলে, আপনি শর্তাবলীর সেটগুলোকে এমন ফাংশনের মধ্যে রাখতে চাইতে পারেন যা আপনার নিয়মাবলীর মধ্যে পুনরায় ব্যবহার করা যাবে। নিরাপত্তা নিয়মগুলো কাস্টম ফাংশন সমর্থন করে। কাস্টম ফাংশনের সিনট্যাক্স কিছুটা জাভাস্ক্রিপ্টের মতো, কিন্তু নিরাপত্তা নিয়মের ফাংশনগুলো একটি ডোমেইন-স্পেসিফিক ল্যাঙ্গুয়েজে লেখা হয়, যার কিছু গুরুত্বপূর্ণ সীমাবদ্ধতা রয়েছে:
- ফাংশনে শুধুমাত্র একটি
returnস্টেটমেন্ট থাকতে পারে। এতে কোনো অতিরিক্ত লজিক থাকতে পারে না। উদাহরণস্বরূপ, এটি লুপ চালাতে বা বাহ্যিক পরিষেবা কল করতে পারে না। - ফাংশনগুলো যে স্কোপে সংজ্ঞায়িত করা হয়, সেই স্কোপের ফাংশন এবং ভেরিয়েবল স্বয়ংক্রিয়ভাবে অ্যাক্সেস করতে পারে। উদাহরণস্বরূপ,
service cloud.firestoreস্কোপের মধ্যে সংজ্ঞায়িত একটি ফাংশনresourceভেরিয়েবল এবংget()ওexists()এর মতো বিল্ট-ইন ফাংশনগুলো অ্যাক্সেস করতে পারে। - ফাংশনগুলো একে অপরকে কল করতে পারে, কিন্তু পুনরাবৃত্তি (recurs) করতে পারে না। মোট কল স্ট্যাকের গভীরতা ১০-এ সীমাবদ্ধ।
- রুলস ভার্সন
v2তে, ফাংশনগুলোletকীওয়ার্ড ব্যবহার করে ভেরিয়েবল নির্ধারণ করতে পারে। একটি ফাংশনে সর্বোচ্চ ১০টি `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 নিরাপত্তা নিয়মাবলী প্রতিটি কোয়েরিকে তার সম্ভাব্য ফলাফলের নিরিখে মূল্যায়ন করে এবং যদি এটি এমন কোনো ডকুমেন্ট ফেরত দিতে পারে যা পড়ার অনুমতি ক্লায়েন্টের নেই, তবে অনুরোধটি ব্যর্থ করে দেয়। কোয়েরিগুলোকে অবশ্যই আপনার নিরাপত্তা নিয়মাবলী দ্বারা নির্ধারিত সীমাবদ্ধতা মেনে চলতে হবে। নিরাপত্তা নিয়মাবলী এবং কোয়েরি সম্পর্কে আরও জানতে, ‘নিরাপদে ডেটা কোয়েরি করা’ দেখুন।
পরবর্তী পদক্ষেপ
- নিরাপত্তা নিয়মাবলী আপনার কোয়েরিগুলোকে কীভাবে প্রভাবিত করে তা জানুন।
- নিরাপত্তা বিধি কীভাবে গঠন করতে হয় তা শিখুন।
- নিরাপত্তা বিধি নির্দেশিকাটি পড়ুন।
- আপনার যে অ্যাপগুলো Cloud Storage for Firebase ব্যবহার করে, সেগুলোর জন্য Cloud Firestore ডকুমেন্ট অ্যাক্সেস করে এমন Cloud Storage Security Rules কন্ডিশন কীভাবে লিখতে হয় তা শিখে নিন।