ماهي Firebase Security Rules ؟
هو عبارة عن ملف JSON يحتوي على إعدادات الكتابة والقراءة في قاعدة البيانات Firebase Database ,أي من الذي يستطيع كتابة وقراءة أي بيانات في قاعدة البيانات.
عندما تتم أي عملية قراءة أو كتابة على قاعدة البيانات فإنه يتم الرجوع الى هذا الملف والتحقق من الصلاحيات المطلوبة ,وعند مطابقة الصلاحيات ستتم عملية الكتابة أو القراءة.
عند رفض عملية القراءة او الكتابة فإن العملية عند Client في الأندرويد على سبيل المثال ستعود ب Failed, Permissions Denied .
ملاحظة:هذه الإعدادات سيتم تجاهلها عند استخدام Firebase Admin SDK ,عند استخدام Cloud Functions مثلاً
نتوجه الى Firebase Console لنرى شكل هذه الإعدادات
إفتراضياً ستكون الإعدادات بهذا الشكل.
بهذا الشكل فقط المستخدمين الذين قامو بتسجيل الدخول باستخدام Firebase Auth يمكنهم الكتابة والقراءة
{
"rules": {
".read": "auth != null",
".write": "auth != null"
}
}
ولنتأكد من الموضوع يمكننا استخدام ميزة Simulator الموجودة في Firebase Console ,وهو عبارة عن محاكي يمكننا تجربة عملية قراءة أو كتابة وهمية لنرى هل تمت أم لا.
بهذا الشكل قمنا بتجربة عملية قراءة على الRef الرئيسي / ,وكما نرى Authenticated لم نقم بتفعيلها أي أن المستخدم لم يقم بتسجيل الدخول
ونرى على اليسار السطر الذي قام بالتحكم بالعملية.
ونفس الأمر ينطبق بالنسبة لصلاحيات الكتابة
الآن لنجرب أن نقوم بتشغيل Authenticated ,أي أن المستخدم قام بتسجيل الدخول
وعند تشغيل هذا الخيار سنرى أنه يمكننا اختيار نوع المستخدم ,هل هو Anonymous أم Facebook او Google الخ.. مع وجود UID
فعلى سبيل المثال يمكننا فقط جعل المستخدمين الذين قامو بتسجيل الدخول عبر Google أن يقومو بعمل قراءة او كتابة من قاعدة البيانات كما سنشاهد لاحقاً
عموماً نقوم باختيار أي نوع ونعمل Run
وسنرى أنه تمت عملية القراءة بنجاح مع وجود السطر الذي قام بإعطاء الصلاحية
إذا أردنا إعطاء الصلاحيات لأي شخص على هذا الكوكب :D بدون تسجيل دخول فيمكنك ذلك عبر
{
"rules": {
".read": true,
".write": true
}
}
ملاحظة:بهذا الشكل يمكن أي شخص أن يقوم بحذف كافة البيانات لديك عبر أمر Curl واحد!
والعكس اذا أردت منع أي شخص من استخدام هذه البيانات
بهذا الشكل لن يستطيع أي شخص وحتى الذين قامو بتسجيل الدخول من عرض او الكتابة على قاعدة البيانات
{
"rules": {
".read": false,
".write": false
}
}
تمكين القراءة او الكتابة لنوع معين
سنقوم بجعل فقط المستخدمين الذين قامو بتسجيل الدخول عبر Google على سبيل المثال من عرض او كتابة البيانات
قمنا بالتأكد من المستخدم قام بتسجيل الدخول وأيضاً auth.provider هو Google
{
"rules": {
".read": "auth != null && auth.provider === 'google'",
".write": "auth != null && auth.provider === 'google'"
}
}
نفس الأمر ينطبق على Facebook
{
"rules": {
".read": "auth != null && auth.provider === 'facebook'",
".write": "auth != null && auth.provider === 'facebook'"
}
}
Facebook و Google مع بعضهم البعض
{
"rules": {
".read": "auth != null && auth.provider === 'google' ||
auth.provider === 'facebook'",
".write": "auth != null && auth.provider === 'google' ||
auth.provider === 'facebook'"
}
}
التحكم فقط من خلال المدير او Admin
لنفترض أن لدينا تطبيق يحتوي على بعض المطاعم ومعلوماتها ويمكن للمستخدم رؤية المطعم ومكانه وتقييمه والخ..
ونريد أن يكون فقط للمدير أو Admin الصلاحية لحذف أو تعديل بيانات المطعم, وللمستخدم العادي الصلاحية فقط في عرض بيانات المطعم
سيكون لدينا في قاعدة البيانات حقل Users سيكون بهم كافة المستخدمين من ضمنهم المدير او Admin
بهذا الشكل
users
u283210das0sada
name: "User1"
u32s929s02ads92
name: "User2"
الآن سنقوم بجعل المستخدم الأول Admin
وذلك عبر اضافة حقل isAdmin وجعل قيمته true
users
u283210das0sada
isAdmin : true
name: "User1"
u32s929s02ads92
name: "User2"
الآن نعود الى Firebase Security Rules لنضيف هذا الشرط
بالنسبة لإعدادات القراءة فقمنا بتفعيلها للمستخدمين الذين قامو بتسجيل الدخول
أما بالنسبة للكتابة فقمنا بالتأكد أولا من أن المستخدم قد قام بتسجيل الدخول وأيضاً قمنا بالتحقق من أن الحقل 'users' يحتوي على uid وداخل هذا uid يجب أن يحتوي على الحقل isAdmin وقيمته true
الآن اذا قمنا بالتجربة على أي user ليس لديه صلاحية isAdmin : true فإنه لايمكنه تعديل أو كتابة أي شيئ
{
"rules": {
".read":"auth != null",
".write":"auth != null && root.child('users')
.child(auth.uid).child('isAdmin').val() == true"
}
}
كل ماسبق كنا نقوم بجعل القواعد عامة, أي أنها تنطبق على كافة Nodes (الحقول) في الداتابيز ,ولكن ماذا اذا أردنا بعض التخصيص ,بمعنى أنه نريد تخصيص قواعد معينة لكل حقل في الداتابيز.
لفهم الموضوع أكثر سنفترض أنه لدينا تطبيق دردشة ونريد اذا كان المستخدم الأول قد قام بحظر المستخدم الثاني,عندها سنقوم بمنع المستخدم الثاني من رؤية صورة البروفايل الخاصة بالمستخدم الأول
لنفترض أنه لدينا نفس الStrcuture السابق لقاعدة البيانات ولكن بإضافة رابط الصورة الخاصة بكل مستخدم
users
u283210das0sada
name: "User1"
photo:"https://......"
u32s929s02ads92
name: "User2"
photo:"https://......"
الآن سنقوم بإنشاء حقل خاص blockedUsers يحتوي على المستخدمين الذين قامو بعمل حظر لمستخدمين آخرين
بهذا الشكل على سبيل المثال
blockedUsers
uid1
uid2:true
uid3:true
..............
..............
عندما يقوم المستخدم الأول User1 بحظر المستخدم الثاني User2 فسيصبح بهذا الشكل
users
u283210das0sada
name: "User1"
photo:"https://......"
u32s929s02ads92
name: "User2"
photo:"https://......"
blockedUsers
u283210das0sada
u32s929s02ads92 : true
نعود الآن الى Secuirty Rules
وداخل القوسين rules نضع القواعد الخاصة بالحقل "users' وداخله قمنا بتعريف بما يسمى ب 'Wildcard' ($) ,اذا كنت قد استخدمت Cloud Functions سابقاً فإنها تعتمد على نفس المبدأ
والفكرة هي الحصول القيمة داخل هذا الحقل ففي حالتنا هذه قمنا بأخذ uid الذي يحاول المستخدم الحصول على هذه المعلومات (المستخدم الثاني User2يحاول الحصول على بيانات المستخدم الثاني)
ويمكنك تسميتها بأي اسم بدل من UID ولكن يجب عليك وضع اشارة $ قبلها
ثم قمنا بوضع القواعد فقط على حقل photo ووضعنا قواعد الكتابة(سنغيرها لاحقاً)
وبالنسبة للقراءة فإنه يجب أن يكون المستخدم قد قام بتسجيل الدخول أن يكون الحقل 'blockedUsers/$uid' لا يحتوي على uid الشخص الثاني
{
"rules": {
"users":{
"$uid":{
"photo":{
".write":"auth != null",
".read": "auth != null && !root.child('blockedUsers')
.child($uid).child(auth.uid).exists()"
}
}
}
}
}
سنجرب على Simulator ونضع uid الشخص المحظور
وعند وضع uid اخر على سبيل المثال تتم عملية القراءة بنجاح
اذا قمنا بتجريب نفس الطريقة على الحقل name فإنه سيتم رفض العملية وذلك لأننا لم نقم بتحديد أية قواعد لهذا الحقل,كنت أتمنى لو أنه بإمكاننا تحديد فقط القواعد للحقول التي نريدها ونستطيع وضع قاعدة عامة عند عدم تواجد قاعدة خاصة لهذا الحقل.
لهذا سنقوم بتحديد قاعدة للحقل name ونريد أن يستطيع أي شخص وحتى ان كان محظوراً من رؤية بيانات الشخص الآخر
{
"rules": {
"users":{
"$uid":{
"photo":{
".write":"auth != null,
".read": "auth != null && !root.child('blockedUsers')
.child($uid).child(auth.uid).exists()"
},
"name":{
".write":"auth != null",
".read": "auth != null"
}
}
}
}
}
الآن نريد تأمين بيانات المستخدم بشكل أكبر عن طريق جعل المستخدم نفسه فقط من أن يستطيع تغيير بياناته
وسنستخدم نفس الطريقة عبر Wildcard
قمنا بالتحقق من أن auth.uid وهو uid الشخص الذي ينفذ الطلب من أنه يساوي $uid
{
"rules": {
"users":{
"$uid":{
"photo":{
".write":"auth != null && auth.uid === $uid",
".read": "auth != null && !root.child('blockedUsers')
.child($uid).child(auth.uid).exists()"
},
"name":{
".write":"auth != null && auth.uid === $uid",
".read": "auth != null"
}
}
}
}
}
اذا قمنا بمحاولة اضافة شخص ما الى blockedUsers فسيظهر لنا خطأ :/ وذلك لأنه لم تتم تحديد قاعدة لهذا الحقل
وسنجعل فقط المستخدم نفسه من عرض وكتابة البيانات
{
"rules": {
"users":{
"$uid":{
"photo":{
".write":"auth != null && auth.uid === $uid",
".read": "auth != null && !root.child('blockedUsers')
.child($uid).child(auth.uid).exists()"
},
"name":{
".write":"auth != null && auth.uid === $uid",
".read": "auth != null"
}
}
},
"blockedUsers":{
"$uid":{
".read":"auth != null && auth.uid === $uid",
".write":"auth != null && auth.uid === $uid"
}
}
}
}
بعض المصادر التي قد تهمك
لايوجد لديك حساب في عالم البرمجة؟
تحب تنضم لعالم البرمجة؟ وتنشئ عالمك الخاص، تنشر المقالات، الدورات، تشارك المبرمجين وتساعد الآخرين، اشترك الآن بخطوات يسيرة !