التعرف على البنية الأساسية للغة قواعد أمان قاعدة البيانات في الوقت الفعلي

تتيح لك قواعد أمان "قاعدة بيانات Firebase في الوقت الفعلي" التحكّم في الوصول إلى البيانات المخزّنة في قاعدة بياناتك. تسمح لك بنية القواعد المرنة بإنشاء قواعد تتطابق مع أي شيء، بدءًا من جميع عمليات الكتابة إلى قاعدة بياناتك ووصولاً إلى العمليات على العقد الفردية.

قواعد أمان "قاعدة بيانات Realtime" هي إعدادات تعريفية لقاعدة بياناتك. وهذا يعني أنّه يتمّ تحديد القواعد بشكل منفصل عن منطق المنتج. لهذه الميزة العديد من المزايا: لا تتحمّل التطبيقات العميلة مسؤولية فرض الأمان، ولن تؤدي عمليات التنفيذ التي تتضمّن أخطاء إلى تعريض بياناتك للخطر، والأهم من ذلك، ليس هناك حاجة إلى وسيط مثل الخادم لحماية البيانات من العالم الخارجي.

يوضّح هذا الموضوع البنية الأساسية لقواعد أمان "قاعدة بيانات الوقت الفعلي" والصيغة الأساسية المستخدَمة لإنشاء قواعد قواعد كاملة.

تنظيم قواعد الأمان

تتكوّن قواعد أمان "قاعدة بيانات الوقت الفعلي" من تعبيرات مشابهة لـ JavaScript مضمّنة في مستند JSON. يجب أن تتّبع بنية قواعدك بنية البيانات التي تخزّنها في قاعدة بياناتك.

تحدِّد القواعد الأساسية مجموعة من العقد التي يجب تأمينها، وطرق الوصول (مثل القراءة والكتابة) المُستخدَمة، والشروط التي يتم بموجبها السماح بالوصول أو رفضه. في الأمثلة التالية، ستكون الشروط عبارة عن عبارات true و false بسيطة، ولكن في الموضوع التالي سنتناول طرقًا أكثر ديناميكية ل expressed conditions.

على سبيل المثال، إذا كنا نحاول تأمين child_node ضمن parent_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/ تحتوي على عنصر فرعي baz بالقيمة true. لا تُحدث قاعدة ".read": false ضمن /foo/bar/ أثرًا هنا، لأنّه لا يمكن إلغاء الإذن بالوصول من خلال مسار فرعي.

على الرغم من أنّه قد لا يبدو واضحًا على الفور، إلا أنّ هذا جزء قوي من لغة القواعد ويسمح بتنفيذ امتيازات وصول معقّدة جدًا بأقل جهد. سيتم توضيح ذلك عند التطرق إلى الأمان المستنِد إلى المستخدم لاحقًا في هذا الدليل.

يُرجى العلم أنّ قواعد .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 هذا في استهداف تطبيق Clip.
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 هذا في استهداف تطبيق Clip.
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
})
جافا
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، يمكننا ملاحظة أنّه تم رفض عملية القراءة لأنّه لم تسمح أي قاعدة قراءة بالوصول إلى مسار /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 هذا في استهداف تطبيق Clip.
FIRDatabaseReference *ref = [[FIRDatabase database] reference];
[[ref child:@"records/rec1"] observeSingleEventOfType:FEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
    // SUCCESS!
}];
Swift
ملاحظة: لا يتوفّر منتج Firebase هذا في استهداف تطبيق Clip.
var ref = FIRDatabase.database().reference()
ref.child("records/rec1").observeSingleEventOfType(.Value, withBlock: { snapshot in
    // SUCCESS!
})
جافا
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 التي تعالج هذه الحالات.