التحقّق من صحة البيانات

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

اختَر منتجًا في كل قسم لمعرفة المزيد عن قواعد التحقّق من صحة البيانات.

القيود المفروضة على البيانات الجديدة

Cloud Firestore

إذا أردت التأكّد من عدم إنشاء مستند يتضمّن حقلًا معيّنًا، يمكنك تضمين الحقل في شرط allow. على سبيل المثال، إذا أردت منع إنشاء أي مستندات تحتوي على الحقل ranking، عليك إيقافها في الشرط create.

  service cloud.firestore {
    match /databases/{database}/documents {
      // Disallow
      match /cities/{city} {
        allow create: if !("ranking" in request.resource.data)
      }
    }
  }

Realtime Database

إذا أردت التأكّد من عدم إضافة بيانات تحتوي على قيم معيّنة إلى قاعدة البيانات، عليك تضمين هذه القيمة في قواعدك ومنعها من عمليات الكتابة. على سبيل المثال، إذا أردت رفض أي عمليات كتابة تحتوي على قيم ranking ، عليك عدم ال��ماح بعمليات الكتابة لأي مستندات تتضمّن قيم ranking.

  {
    "rules": {
      // Write is allowed for all paths
      ".write": true,
      // Allows writes only if new data doesn't include a `ranking` child value
      ".validate": "!newData.hasChild('ranking')
    }
  }

Cloud Storage

إذا أردت التأكّد من عدم إنشاء ملف يحتوي على بيانات وصفية معيّنة، يمكنك تضمين البيانات الوصفية في الشرط allow. على سبيل المثال، إذا كنت تريد منع إنشاء أي ملفات تحتوي على بيانات وصفية ranking، عليك إيقافها في شرط create.

  service firebase.storage {
    match /b/{bucket}/o {
      match /files/{fileName} {
      // Disallow
        allow create: if !("ranking" in request.resource.metadata)
      }
    }
  }

استخدام البيانات الحالية في Firebase Security Rules

Cloud Firestore

تخزّن العديد من التطبيقات معلومات التحكّم في الوصول كحقول في المستندات في قاعدة البيانات. يمكن لـ 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، اطّلِع على المستندات المرجعية.

عند كتابة البيانات، قد تحتاج إلى مقارنة البيانات الواردة بالبيانات الحالية. يتيح لك ذلك إجراء عمليات مثل التأكّد من عدم تغيير حقل معيّن، أو أنّ الحقل قد زاد بمقدار واحد فقط، أو أنّ القيمة الجديدة هي أسبوع واحد على الأقل في المستقبل. في هذه الحالة، إذا كانت مجموعة القواعد تسمح بعملية ال��تابة المعلّقة، سيحتوي المتغيّر 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;
      }
    }
  }

Realtime Database

في Realtime Database، استخدِم قواعد .validate لفرض بنى البيانات والتحقّق من صحة تنسيق البيانات ومحتواها. Rules تنفيذ .validate قاعدة بعد التأكّد من أنّ قاعدة .write تمنح إذن الوصول

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

ضَع في اعتبارك .validate القواعد التالية:

  {
    "rules": {
      // write is allowed for all paths
      ".write": true,
      "widget": {
        // a valid widget must have attributes "color" and "size"
        // allows deleting widgets (since .validate is not applied to delete rules)
        ".validate": "newData.hasChildren(['color', 'size'])",
        "size": {
          // the value of "size" must be a number between 0 and 99
          ".validate": "newData.isNumber() &&
                        newData.val() >= 0 &&
                        newData.val() <= 99"
        },
        "color": {
          // the value of "color" must exist as a key in our mythical
          // /valid_colors/ index
          ".validate": "root.child('valid_colors/' + newData.val()).exists()"
        }
      }
    }
  }

ستؤدي كتابة طلبات إلى قاعدة بيانات باستخدام القواعد المذكورة أعلاه إلى النتائج التالية:

JavaScript
var ref = db.ref("/widget");

// PERMISSION_DENIED: does not have children color and size
ref.set('foo');

// PERMISSION DENIED: does not have child color
ref.set({size: 22});

// PERMISSION_DENIED: size is not a number
ref.set({ size: 'foo', color: 'red' });

// SUCCESS (assuming 'blue' appears in our colors list)
ref.set({ size: 21, color: 'blue'});

// If the record already exists and has a color, this will
// succeed, otherwise it will fail since newData.hasChildren(['color', 'size'])
// will fail to validate
ref.child('size').set(99);
Objective-C
ملاحظة: لا يتوفّر منتج Firebase هذا على هدف "مقتطف التطبيق".
FIRDatabaseReference *ref = [[[FIRDatabase database] reference] child: @"widget"];

// PERMISSION_DENIED: does not have children color and size
[ref setValue: @"foo"];

// PERMISSION DENIED: does not have child color
[ref setValue: @{ @"size": @"foo" }];

// PERMISSION_DENIED: size is not a number
[ref setValue: @{ @"size": @"foo", @"color": @"red" }];

// SUCCESS (assuming 'blue' appears in our colors list)
[ref setValue: @{ @"size": @21, @"color": @"blue" }];

// If the record already exists and has a color, this will
// succeed, otherwise it will fail since newData.hasChildren(['color', 'size'])
// will fail to validate
[[ref child:@"size"] setValue: @99];
Swift
ملاحظة: لا يتوفّر منتج Firebase هذا على هدف "مقتطف التطبيق".
var ref = FIRDatabase.database().reference().child("widget")

// PERMISSION_DENIED: does not have children color and size
ref.setValue("foo")

// PERMISSION DENIED: does not have child color
ref.setValue(["size": "foo"])

// PERMISSION_DENIED: size is not a number
ref.setValue(["size": "foo", "color": "red"])

// SUCCESS (assuming 'blue' appears in our colors list)
ref.setValue(["size": 21, "color": "blue"])

// If the record already exists and has a color, this will
// succeed, otherwise it will fail since newData.hasChildren(['color', 'size'])
// will fail to validate
ref.child("size").setValue(99);
Java
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference ref = database.getReference("widget");

// PERMISSION_DENIED: does not have children color and size
ref.setValue("foo");

// PERMISSION DENIED: does not have child color
ref.child("size").setValue(22);

// PERMISSION_DENIED: size is not a number
Map<String,Object> map = new HashMap<String, Object>();
map.put("size","foo");
map.put("color","red");
ref.setValue(map);

// SUCCESS (assuming 'blue' appears in our colors list)
map = new HashMap<String, Object>();
map.put("size", 21);
map.put("color","blue");
ref.setValue(map);

// If the record already exists and has a color, this will
// succeed, otherwise it will fail since newData.hasChildren(['color', 'size'])
// will fail to validate
ref.child("size").setValue(99);
REST
# PERMISSION_DENIED: does not have children color and size
curl -X PUT -d 'foo' \
https://docs-examples.firebaseio.com/rest/securing-data/example.json

# PERMISSION DENIED: does not have child color
curl -X PUT -d '{"size": 22}' \
https://docs-examples.firebaseio.com/rest/securing-data/example.json

# PERMISSION_DENIED: size is not a number
curl -X PUT -d '{"size": "foo", "color": "red"}' \
https://docs-examples.firebaseio.com/rest/securing-data/example.json

# SUCCESS (assuming 'blue' appears in our colors list)
curl -X PUT -d '{"size": 21, "color": "blue"}' \
https://docs-examples.firebaseio.com/rest/securing-data/example.json

# If the record already exists and has a color, this will
# succeed, otherwise it will fail since newData.hasChildren(['color', 'size'])
# will fail to validate
curl -X PUT -d '99' \
https://docs-examples.firebaseio.com/rest/securing-data/example/size.json

Cloud Storage

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

يحتوي الكائن resource على أزواج مفاتيح وقيم مع بيانات وصفية للملف تظهر في الكائن Cloud Storage. يمكن فحص هذه السمات في طلبات read أو write لضمان سلامة البيانات. يتحقّق العنصر resource من البيانات الوصفية في الملفات الحالية في حزمة Cloud Storage.

  service firebase.storage {
    match /b/{bucket}/o {
      match /images {
        match /{fileName} {
          // Allow reads if a custom 'visibility' field is set to 'public'
          allow read: if resource.metadata.visibility == 'public';
        }
      }
    }
  }

يمكنك أيضًا استخدام العنصر request.resource في طلبات write (مثل عمليات التحميل وتعديلات البيانات الوصفية والحذف). يحصل الكائن request.resource على البيانات الوصفية من الملف الذي سيتمّت الكتابة إليه إذا كان write مسموحًا به.

يمكنك استخدام هاتين القيمتين لمنع التحديثات غير المرغوب فيها أو غير المتسقة أو لفرض قيود على التطبيق، مثل نوع الملف أو حجمه.

  service firebase.storage {
    match /b/{bucket}/o {
      match /images {
        // Allow write files to the path "images/*", subject to the constraints:
        // 1) File is less than 5MB
        // 2) Content type is an image
        // 3) Uploaded content type matches existing content type
        // 4) Filename (stored in imageId wildcard variable) is less than 32 characters
        match /{imageId} {
          allow read;
          allow write: if request.resource.size < 5 * 1024 * 1024
                       && request.resource.contentType.matches('image/.*')
                       && request.resource.contentType == resource.contentType
                       && imageId.size() < 32
        }
      }
    }
  }

تتوفّر قائمة كاملة بالسمات في عنصر resource في المستندات المرجعية.