নির্দিষ্ট ক্ষেত্রগুলিতে অ্যাক্সেস নিয়ন্ত্রণ করুন

এই পৃষ্ঠাটি স্ট্রাকচারিং সিকিউরিটি রুলস এবং রাইটিং কন্ডিশন ফর সিকিউরিটি রুলস এর ধারণার উপর ভিত্তি করে তৈরি করা হয়েছে যাতে আপনি কীভাবে Cloud Firestore Security Rules ব্যবহার করে এমন নিয়ম তৈরি করতে পারেন যা ক্লায়েন্টদের একটি ডকুমেন্টের কিছু ফিল্ডে ক্রিয়াকলাপ করতে দেয় কিন্তু অন্যদের নয়।

এমন সময় হতে পারে যখন আপনি নথির স্তরে নয় কিন্তু ক্ষেত্র স্তরে একটি নথিতে পরিবর্তনগুলি নিয়ন্ত্রণ করতে চান৷

উদাহরণস্বরূপ, আপনি একটি ক্লায়েন্টকে একটি নথি তৈরি বা পরিবর্তন করার অনুমতি দিতে চাইতে পারেন, কিন্তু তাদের সেই নথিতে নির্দিষ্ট ক্ষেত্র সম্পাদনা করার অনুমতি দেবেন না। অথবা আপনি প্রয়োগ করতে চাইতে পারেন যে কোনও ক্লায়েন্ট সর্বদা তৈরি করে এমন কোনও নথিতে একটি নির্দিষ্ট ক্ষেত্র রয়েছে। Cloud Firestore Security Rules ব্যবহার করে আপনি কীভাবে এই কাজগুলির মধ্যে কয়েকটি সম্পন্ন করতে পারেন তা এই নির্দেশিকাটি কভার করে।

শুধুমাত্র নির্দিষ্ট ক্ষেত্রগুলির জন্য পড়ার অ্যাক্সেসের অনুমতি দেওয়া হচ্ছে

Cloud Firestore পড়া ডকুমেন্ট লেভেলে সঞ্চালিত হয়। আপনি হয় সম্পূর্ণ নথি পুনরুদ্ধার করুন, অথবা আপনি কিছুই পুনরুদ্ধার করবেন না। একটি আংশিক নথি পুনরুদ্ধার করার কোন উপায় নেই. একটি ডকুমেন্টের মধ্যে নির্দিষ্ট ক্ষেত্রগুলি পড়তে ব্যবহারকারীদের প্রতিরোধ করার জন্য শুধুমাত্র নিরাপত্তা নিয়ম ব্যবহার করা অসম্ভব।

যদি কোনও নথির মধ্যে কিছু নির্দিষ্ট ক্ষেত্র থাকে যা আপনি কিছু ব্যবহারকারীর কাছ থেকে লুকিয়ে রাখতে চান, তবে সর্বোত্তম উপায় হল সেগুলিকে একটি পৃথক নথিতে রাখা। উদাহরণস্বরূপ, আপনি একটি private উপ-সংগ্রহে একটি নথি তৈরি করার কথা বিবেচনা করতে পারেন:

/কর্মচারী/{emp_id}

  name: "Alice Hamilton",
  department: 461,
  start_date: <timestamp>

/কর্মচারী/{emp_id}/private/finances

    salary: 80000,
    bonus_mult: 1.25,
    perf_review: 4.2

তারপর আপনি নিরাপত্তা নিয়ম যোগ করতে পারেন যে দুটি সংগ্রহের জন্য অ্যাক্সেসের বিভিন্ন স্তর আছে। এই উদাহরণে, আমরা কাস্টম প্রমাণীকরণ দাবিগুলি ব্যবহার করছি এই কথা বলার জন্য যে শুধুমাত্র কাস্টম প্রমাণীকরণ দাবির role সাথে Finance সমান ব্যবহারকারীরা একজন কর্মচারীর আর্থিক তথ্য দেখতে পারেন৷

service cloud.firestore {
  match /databases/{database}/documents {
    // Allow any logged in user to view the public employee data
    match /employees/{emp_id} {
      allow read: if request.resource.auth != null
      // Allow only users with the custom auth claim of "Finance" to view
      // the employee's financial data
      match /private/finances {
        allow read: if request.resource.auth &&
          request.resource.auth.token.role == 'Finance'
      }
    }
  }
}

নথি তৈরির ক্ষেত্রে সীমাবদ্ধতা

Cloud Firestore স্কিমলেস, মানে ডকুমেন্টে কোন ফিল্ড রয়েছে তার জন্য ডাটাবেস লেভেলে কোন সীমাবদ্ধতা নেই। যদিও এই নমনীয়তা উন্নয়নকে সহজ করে তুলতে পারে, এমন সময় আসবে যখন আপনি নিশ্চিত করতে চান যে ক্লায়েন্টরা শুধুমাত্র এমন নথি তৈরি করতে পারে যাতে নির্দিষ্ট ক্ষেত্র থাকে, বা অন্য ক্ষেত্র থাকে না।

আপনি request.resource.data অবজেক্টের keys পদ্ধতি পরীক্ষা করে এই নিয়মগুলি তৈরি করতে পারেন। এটি সমস্ত ক্ষেত্রের একটি তালিকা যা ক্লায়েন্ট এই নতুন নথিতে লেখার চেষ্টা করছে৷ hasOnly() বা hasAny() মত ফাংশনগুলির সাথে ফিল্ডের এই সেটটি একত্রিত করে, আপনি যুক্তি যোগ করতে পারেন যা Cloud Firestore ব্যবহারকারী যে ধরনের নথি যোগ করতে পারে তা সীমাবদ্ধ করে৷

নতুন নথিতে নির্দিষ্ট ক্ষেত্র প্রয়োজন

ধরা যাক আপনি নিশ্চিত করতে চান যে একটি restaurant সংগ্রহে তৈরি সমস্ত নথিতে অন্তত একটি name , location এবং city ক্ষেত্র রয়েছে৷ আপনি নতুন নথিতে কীগুলির তালিকায় hasAll() কল করে এটি করতে পারেন।

service cloud.firestore {
  match /databases/{database}/documents {
    // Allow the user to create a document only if that document contains a name
    // location, and city field
    match /restaurant/{restId} {
      allow create: if request.resource.data.keys().hasAll(['name', 'location', 'city']);
    }
  }
}

এটি রেস্তোঁরাগুলিকে অন্যান্য ক্ষেত্রগুলির সাথেও তৈরি করার অনুমতি দেয়, তবে এটি নিশ্চিত করে যে একটি ক্লায়েন্ট দ্বারা তৈরি সমস্ত নথিতে কমপক্ষে এই তিনটি ক্ষেত্র রয়েছে৷

নতুন নথিতে নির্দিষ্ট ক্ষেত্র নিষিদ্ধ করা

একইভাবে, আপনি নিষিদ্ধ ক্ষেত্রগুলির তালিকার বিরুদ্ধে hasAny() ব্যবহার করে নির্দিষ্ট ক্ষেত্র ধারণ করে এমন নথি তৈরি করা থেকে ক্লায়েন্টদের আটকাতে পারেন। এই পদ্ধতিটি সত্য হিসাবে মূল্যায়ন করে যদি একটি নথিতে এই ক্ষেত্রগুলির মধ্যে যেকোনও থাকে, তাই আপনি সম্ভবত নির্দিষ্ট ক্ষেত্রগুলি নিষিদ্ধ করার জন্য ফলাফলটি অস্বীকার করতে চান৷

উদাহরণস্বরূপ, নিম্নলিখিত উদাহরণে, ক্লায়েন্টদের এমন একটি নথি তৈরি করার অনুমতি দেওয়া হয় না যাতে একটি average_score বা rating_count ক্ষেত্র রয়েছে কারণ এই ক্ষেত্রগুলি পরবর্তী সময়ে একটি সার্ভার কল দ্বারা যুক্ত করা হবে।

service cloud.firestore {
  match /databases/{database}/documents {
    // Allow the user to create a document only if that document does *not*
    // contain an average_score or rating_count field.
    match /restaurant/{restId} {
      allow create: if (!request.resource.data.keys().hasAny(
        ['average_score', 'rating_count']));
    }
  }
}

নতুন নথির জন্য ক্ষেত্রগুলির একটি অনুমোদিত তালিকা তৈরি করা

নতুন নথিতে নির্দিষ্ট ক্ষেত্র নিষিদ্ধ করার পরিবর্তে, আপনি শুধুমাত্র সেই ক্ষেত্রগুলির একটি তালিকা তৈরি করতে চাইতে পারেন যেগুলি নতুন নথিতে স্পষ্টভাবে অনুমোদিত৷ তারপরে আপনি hasOnly() ফাংশনটি ব্যবহার করতে পারেন তা নিশ্চিত করতে যে কোনও নতুন নথিতে শুধুমাত্র এই ক্ষেত্রগুলি (বা এই ক্ষেত্রগুলির একটি উপসেট) রয়েছে এবং অন্য কোনও নয়৷

service cloud.firestore {
  match /databases/{database}/documents {
    // Allow the user to create a document only if that document doesn't contain
    // any fields besides the ones listed below.
    match /restaurant/{restId} {
      allow create: if (request.resource.data.keys().hasOnly(
        ['name', 'location', 'city', 'address', 'hours', 'cuisine']));
    }
  }
}

প্রয়োজনীয় এবং ঐচ্ছিক ক্ষেত্র একত্রিত করা

কিছু ক্ষেত্রের প্রয়োজন এবং অন্যদের অনুমতি দেওয়ার জন্য আপনি আপনার নিরাপত্তা নিয়মে hasAll এবং hasOnly অপারেশনগুলিকে একত্রিত করতে পারেন। উদাহরণস্বরূপ, এই উদাহরণের জন্য প্রয়োজন যে সমস্ত নতুন নথিতে name , location এবং city ক্ষেত্র রয়েছে এবং ঐচ্ছিকভাবে address , hours এবং cuisine ক্ষেত্রগুলিকে অনুমতি দেয়৷

service cloud.firestore {
  match /databases/{database}/documents {
    // Allow the user to create a document only if that document has a name,
    // location, and city field, and optionally address, hours, or cuisine field
    match /restaurant/{restId} {
      allow create: if (request.resource.data.keys().hasAll(['name', 'location', 'city'])) &&
       (request.resource.data.keys().hasOnly(
           ['name', 'location', 'city', 'address', 'hours', 'cuisine']));
    }
  }
}

একটি বাস্তব-বিশ্বের দৃশ্যে, আপনি আপনার কোডের নকল এড়াতে এবং আরও সহজে ঐচ্ছিক এবং প্রয়োজনীয় ক্ষেত্রগুলিকে একক তালিকায় একত্রিত করতে এই যুক্তিটিকে একটি সহায়ক ফাংশনে স্থানান্তর করতে চাইতে পারেন, যেমন:

service cloud.firestore {
  match /databases/{database}/documents {
    function verifyFields(required, optional) {
      let allAllowedFields = required.concat(optional);
      return request.resource.data.keys().hasAll(required) &&
        request.resource.data.keys().hasOnly(allAllowedFields);
    }
    match /restaurant/{restId} {
      allow create: if verifyFields(['name', 'location', 'city'],
        ['address', 'hours', 'cuisine']);
    }
  }
}

আপডেটে ক্ষেত্র সীমাবদ্ধ করা হচ্ছে

একটি সাধারণ নিরাপত্তা অনুশীলন হল শুধুমাত্র ক্লায়েন্টদের কিছু ক্ষেত্র সম্পাদনা করার অনুমতি দেওয়া এবং অন্যদের নয়। আপনি শুধুমাত্র পূর্ববর্তী বিভাগে বর্ণিত request.resource.data.keys() তালিকা দেখে এটি সম্পন্ন করতে পারবেন না, যেহেতু এই তালিকাটি সম্পূর্ণ নথির প্রতিনিধিত্ব করে কারণ এটি আপডেটের দেখাশোনা করবে, এবং সেইজন্য সেই ক্ষেত্রগুলি অন্তর্ভুক্ত করবে যা ক্লায়েন্ট করেনি। পরিবর্তন

যাইহোক, যদি আপনি diff() ফাংশনটি ব্যবহার করেন, আপনি resource.data অবজেক্টের সাথে request.resource.data তুলনা করতে পারেন, যা আপডেটের আগে ডাটাবেসের নথিটিকে উপস্থাপন করে। এটি একটি mapDiff অবজেক্ট তৈরি করে, যা দুটি ভিন্ন মানচিত্রের মধ্যে সমস্ত পরিবর্তন ধারণকারী একটি বস্তু।

এই ম্যাপডিফ-এ affectedKeys() পদ্ধতিতে কল করার মাধ্যমে, আপনি একটি সম্পাদনায় পরিবর্তিত ক্ষেত্রগুলির একটি সেট নিয়ে আসতে পারেন। তারপর আপনি hasOnly() বা hasAny() মত ফাংশন ব্যবহার করতে পারেন যাতে নিশ্চিত করা যায় যে এই সেটে কিছু আইটেম আছে (বা নেই)।

পরিবর্তন করা থেকে কিছু ক্ষেত্র প্রতিরোধ

affectedKeys() দ্বারা উত্পন্ন সেটে hasAny() পদ্ধতি ব্যবহার করে এবং তারপর ফলাফলটি অস্বীকার করে, আপনি যে কোনও ক্লায়েন্ট অনুরোধ প্রত্যাখ্যান করতে পারেন যা আপনি পরিবর্তন করতে চান না এমন ক্ষেত্রগুলি পরিবর্তন করার চেষ্টা করে।

উদাহরণস্বরূপ, আপনি ক্লায়েন্টদের একটি রেস্টুরেন্ট সম্পর্কে তথ্য আপডেট করার অনুমতি দিতে চাইতে পারেন কিন্তু তাদের গড় স্কোর বা পর্যালোচনার সংখ্যা পরিবর্তন করবেন না।

service cloud.firestore {
  match /databases/{database}/documents {
    match /restaurant/{restId} {
      // Allow the client to update a document only if that document doesn't
      // change the average_score or rating_count fields
      allow update: if (!request.resource.data.diff(resource.data).affectedKeys()
        .hasAny(['average_score', 'rating_count']));
    }
  }
}

শুধুমাত্র নির্দিষ্ট ক্ষেত্র পরিবর্তন করার অনুমতি দেওয়া হচ্ছে

আপনি যে ক্ষেত্রগুলি পরিবর্তন করতে চান না তা নির্দিষ্ট করার পরিবর্তে, আপনি পরিবর্তন করতে চান এমন ক্ষেত্রগুলির একটি তালিকা নির্দিষ্ট করতে আপনি hasOnly() ফাংশনটিও ব্যবহার করতে পারেন। এটি সাধারণত আরও সুরক্ষিত বলে বিবেচিত হয় কারণ যেকোন নতুন নথির ক্ষেত্রে লেখাগুলি ডিফল্টরূপে অননুমোদিত হয় যতক্ষণ না আপনি আপনার নিরাপত্তা নিয়মে স্পষ্টভাবে অনুমতি দেন।

উদাহরণস্বরূপ, average_score এবং rating_count ফিল্ডকে অনুমোদন না করে, আপনি নিরাপত্তা নিয়ম তৈরি করতে পারেন যা ক্লায়েন্টদের শুধুমাত্র name , location , city , address , hours এবং cuisine ক্ষেত্র পরিবর্তন করতে দেয়।

service cloud.firestore {
  match /databases/{database}/documents {
    match /restaurant/{restId} {
    // Allow a client to update only these 6 fields in a document
      allow update: if (request.resource.data.diff(resource.data).affectedKeys()
        .hasOnly(['name', 'location', 'city', 'address', 'hours', 'cuisine']));
    }
  }
}

এর মানে হল যে, যদি আপনার অ্যাপের ভবিষ্যতের কিছু পুনরাবৃত্তিতে, রেস্তোরাঁর নথিতে একটি telephone ক্ষেত্র অন্তর্ভুক্ত থাকে, তাহলে সেই ক্ষেত্রটি সম্পাদনা করার প্রচেষ্টা ব্যর্থ হবে যতক্ষণ না আপনি ফিরে যান এবং আপনার নিরাপত্তা নিয়মের hasOnly() তালিকায় সেই ক্ষেত্রটি যোগ করেন।

ক্ষেত্রের ধরন বলবৎকরণ

Cloud Firestore স্কিমলেস হওয়ার আরেকটি প্রভাব হল যে নির্দিষ্ট ক্ষেত্রে কি ধরনের ডেটা সংরক্ষণ করা যেতে পারে তার জন্য ডাটাবেস স্তরে কোনো প্রয়োগ নেই। এটি এমন কিছু যা আপনি নিরাপত্তা বিধিতে প্রয়োগ করতে পারেন, তবে, is অপারেটরের সাথে।

উদাহরণ স্বরূপ, নিম্নলিখিত নিরাপত্তা নিয়মটি প্রয়োগ করে যে একটি পর্যালোচনার score ক্ষেত্র একটি পূর্ণসংখ্যা হতে হবে, headline , content , এবং author_name ক্ষেত্রগুলি হল স্ট্রিং, এবং review_date হল একটি টাইমস্ট্যাম্প৷

service cloud.firestore {
  match /databases/{database}/documents {
    match /restaurant/{restId} {
      // Restaurant rules go here...
      match /review/{reviewId} {
        allow create: if (request.resource.data.score is int &&
          request.resource.data.headline is string &&
          request.resource.data.content is string &&
          request.resource.data.author_name is string &&
          request.resource.data.review_date is timestamp
        );
      }
    }
  }
}

is অপারেটরের জন্য বৈধ ডেটা প্রকারগুলি হল bool , bytes , float , int , list , latlng , number , path , map , string এবং timestampis অপারেটর constraint , duration , set , এবং map_diff ডেটা প্রকারগুলিকেও সমর্থন করে, কিন্তু যেহেতু এগুলি নিরাপত্তা নিয়মের ভাষা দ্বারা তৈরি হয় এবং ক্লায়েন্টদের দ্বারা উত্পন্ন হয় না, আপনি খুব কমই ব্যবহারিক অ্যাপ্লিকেশনগুলিতে এগুলি ব্যবহার করেন৷

list এবং map ডেটা প্রকারের জেনেরিক বা টাইপ আর্গুমেন্টের জন্য সমর্থন নেই। অন্য কথায়, আপনি একটি নির্দিষ্ট ক্ষেত্রে একটি তালিকা বা একটি মানচিত্র রয়েছে তা প্রয়োগ করতে নিরাপত্তা নিয়ম ব্যবহার করতে পারেন, কিন্তু আপনি প্রয়োগ করতে পারবেন না যে একটি ক্ষেত্রের সমস্ত পূর্ণসংখ্যা বা সমস্ত স্ট্রিংগুলির একটি তালিকা রয়েছে৷

একইভাবে, আপনি একটি তালিকা বা একটি মানচিত্রে নির্দিষ্ট এন্ট্রির জন্য মান প্রয়োগ করতে নিরাপত্তা নিয়ম ব্যবহার করতে পারেন (যথাক্রমে ব্র্যাকেট নোটেশন বা কী নাম ব্যবহার করে), কিন্তু একটি মানচিত্র বা একটি তালিকাতে সমস্ত সদস্যের ডেটা প্রকারগুলি প্রয়োগ করার জন্য কোনও শর্টকাট নেই একবার

উদাহরণস্বরূপ, নিম্নলিখিত নিয়মগুলি নিশ্চিত করে যে একটি নথির একটি tags ক্ষেত্রে একটি তালিকা রয়েছে এবং প্রথম এন্ট্রিটি একটি স্ট্রিং। এটিও নিশ্চিত করে যে product ক্ষেত্রের একটি মানচিত্র রয়েছে যার ফলে একটি পণ্যের নাম রয়েছে যা একটি স্ট্রিং এবং একটি পরিমাণ যা একটি পূর্ণসংখ্যা।

service cloud.firestore {
  match /databases/{database}/documents {
  match /orders/{orderId} {
    allow create: if request.resource.data.tags is list &&
      request.resource.data.tags[0] is string &&
      request.resource.data.product is map &&
      request.resource.data.product.name is string &&
      request.resource.data.product.quantity is int
      }
    }
  }
}

একটি নথি তৈরি এবং আপডেট করার সময় ক্ষেত্রের ধরনগুলি প্রয়োগ করা প্রয়োজন৷ অতএব, আপনি একটি সহায়ক ফাংশন তৈরি করার কথা বিবেচনা করতে চাইতে পারেন যা আপনি আপনার নিরাপত্তা নিয়মের তৈরি এবং আপডেট উভয় বিভাগেই কল করতে পারেন।

service cloud.firestore {
  match /databases/{database}/documents {

  function reviewFieldsAreValidTypes(docData) {
     return docData.score is int &&
          docData.headline is string &&
          docData.content is string &&
          docData.author_name is string &&
          docData.review_date is timestamp;
  }

   match /restaurant/{restId} {
      // Restaurant rules go here...
      match /review/{reviewId} {
        allow create: if reviewFieldsAreValidTypes(request.resource.data) &&
          // Other rules may go here
        allow update: if reviewFieldsAreValidTypes(request.resource.data) &&
          // Other rules may go here
      }
    }
  }
}

ঐচ্ছিক ক্ষেত্রগুলির জন্য প্রকারগুলি প্রয়োগ করা৷

এটা মনে রাখা গুরুত্বপূর্ণ যে একটি নথিতে অনুরোধ করা request.resource.data.foo যেখানে foo বিদ্যমান নেই একটি ত্রুটির ফলাফল, এবং সেইজন্য সেই কল করার কোনো নিরাপত্তা নিয়ম অনুরোধ অস্বীকার করবে। আপনি request.resource.dataget পদ্ধতি ব্যবহার করে এই পরিস্থিতি পরিচালনা করতে পারেন। get পদ্ধতিটি আপনাকে একটি মানচিত্র থেকে পুনরুদ্ধার করা ক্ষেত্রের জন্য একটি ডিফল্ট যুক্তি প্রদান করতে দেয় যদি সেই ক্ষেত্রটি বিদ্যমান না থাকে।

উদাহরণস্বরূপ, যদি পর্যালোচনা নথিতে একটি ঐচ্ছিক photo_url ক্ষেত্র এবং একটি ঐচ্ছিক tags ক্ষেত্র থাকে যা আপনি যথাক্রমে স্ট্রিং এবং তালিকা যাচাই করতে চান, তাহলে আপনি reviewFieldsAreValidTypes ফাংশনটিকে নিম্নলিখিত মত কিছুতে পুনরায় লেখার মাধ্যমে এটি সম্পন্ন করতে পারেন:

  function reviewFieldsAreValidTypes(docData) {
     return docData.score is int &&
          docData.headline is string &&
          docData.content is string &&
          docData.author_name is string &&
          docData.review_date is timestamp &&
          docData.get('photo_url', '') is string &&
          docData.get('tags', []) is list;
  }

এটি এমন নথিগুলিকে প্রত্যাখ্যান করে যেখানে tags বিদ্যমান, কিন্তু একটি তালিকা নয়, যখন এখনও এমন নথিগুলিকে অনুমতি দেয় যেখানে tags (বা photo_url ) ক্ষেত্র নেই৷

আংশিক লেখা কখনই অনুমোদিত নয়

Cloud Firestore Security Rules সম্পর্কে একটি চূড়ান্ত নোট হল যে তারা হয় ক্লায়েন্টকে একটি নথিতে পরিবর্তন করার অনুমতি দেয়, অথবা তারা সম্পূর্ণ সম্পাদনা প্রত্যাখ্যান করে। আপনি নিরাপত্তা নিয়ম তৈরি করতে পারবেন না যা আপনার নথির কিছু ক্ষেত্রে লেখা গ্রহণ করে যখন একই অপারেশনে অন্যদের প্রত্যাখ্যান করে।