Join us for Firebase Summit on November 10, 2021. Tune in to learn how Firebase can help you accelerate app development, release with confidence, and scale with ease. Register

از شرایط موجود در قوانین پایگاه داده در زمان واقعی استفاده کنید

این راهنما بر اساس یاد هسته زبان قوانین فایربیس امنیت راهنمای به نشان می دهد چگونه برای اضافه کردن شرایط برای خود پایگاه فایربیس بیدرنگ قوانین امنیتی.

بلوک ساختمان اصلی پایگاه بیدرنگ قوانین امنیتی این بیماری است. شرط یک عبارت بولی است که تعیین می کند که آیا یک عملیات خاص باید مجاز یا رد شود. برای قوانین اساسی، با استفاده از true و false لیترال به عنوان شرایط prefectly خوبی کار می کند. اما زبان مقررات امنیتی پایگاه داده در زمان واقعی به شما راه هایی برای نوشتن شرایط پیچیده تر می دهد که می تواند:

  • احراز هویت کاربر را بررسی کنید
  • داده های موجود را در برابر داده های تازه ارائه شده ارزیابی کنید
  • به قسمتهای مختلف پایگاه داده خود دسترسی داشته و آنها را مقایسه کنید
  • اعتبار داده های ورودی
  • از ساختار پرس و جوهای ورودی برای منطق امنیتی استفاده کنید

استفاده از متغیرهای $ برای ضبط بخش های مسیر

شما می توانید بخش هایی از مسیر برای خواندن و یا نوشتن با اعلام متغیرهای ضبط با تصرف $ پیشوند. این به عنوان یک کارت وحشی عمل می کند و ارزش آن کلید را برای استفاده در شرایط قوانین ذخیره می کند:

{
  "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 }
    }
  }
}

احراز هویت

یکی از رایج ترین الگوهای قوانین امنیتی ، کنترل دسترسی بر اساس وضعیت احراز هویت کاربر است. به عنوان مثال ، ممکن است برنامه شما بخواهد به کاربران واردشده اجازه دهد داده ها را بنویسند.

اگر برنامه خود را با استفاده از فایربیس احراز هویت، این request.auth متغیر شامل اطلاعات احراز هویت برای مشتری درخواست داده است. برای کسب اطلاعات بیشتر در مورد request.auth ، و مستندات مرجع .

احراز هویت Firebase با پایگاه داده Firebase Realtime ادغام می شود تا به شما این امکان را می دهد تا با استفاده از شرایط دسترسی به داده ها را بر اساس هر کاربر کنترل کنید. هنگامی که یک کاربر اعتبار از auth متغیر در پایگاه بیدرنگ قوانین قوانین امنیت خود را با اطلاعات کاربر جمعیت. این اطلاعات شامل شناسه خود منحصر به فرد ( uid ) و همچنین داده های حساب مرتبط، مانند یک شناسه فیس بوک و یا یک آدرس ایمیل، و اطلاعات دیگر. اگر یک ارائه دهنده نویسنده سفارشی را پیاده سازی می کنید ، می توانید فیلدهای خود را به میزان باربری کاربر خود اضافه کنید.

این بخش نحوه ترکیب زبان قوانین قوانین امنیتی Firebase Realtime Database با اطلاعات احراز هویت کاربران شما را توضیح می دهد. با ترکیب این دو مفهوم ، می توانید دسترسی به داده ها را بر اساس هویت کاربر کنترل کنید.

auth متغیر

از پیش تعریف شده auth متغیر در قوانین تهی است قبل از احراز هویت می گیرد.

هنگامی که یک کاربر با تصدیق فایربیس تایید آن را از ویژگی های زیر شامل:

تامین کننده روش احراز هویت مورد استفاده ("رمز عبور" ، "ناشناس" ، "فیس بوک" ، "github" ، "google" ، یا "توییتر").
uid شناسه کاربر منحصر به فرد ، تضمین می شود که در همه ارائه دهندگان منحصر به فرد است.
نشانه محتویات شناسه شناسه Firebase Auth. مستندات مرجع برای مشاهده auth.token برای جزئیات بیشتر.

در اینجا یک مثال حکومت که با استفاده از است auth متغیر به اطمینان حاصل شود که هر کاربر تنها می تواند به یک مسیر کاربر خاص ارسال:

{
  "rules": {
    "users": {
      "$user_id": {
        // grants write access to the owner of this user account
        // whose uid must exactly match the key ($user_id)
        ".write": "$user_id === auth.uid"
      }
    }
  }
}

ساختار پایگاه داده خود را برای پشتیبانی از شرایط احراز هویت

معمولاً ساختار پایگاه داده شما به گونه ای است که نوشتن قوانین را آسان تر می کند. یک الگوی مشترک برای ذخیره دادههای کاربر در پایگاه داده بیدرنگ است برای ذخیره تمام کاربران خود را در یک users گره ای که کودکان هستند uid ارزش برای هر کاربر. اگر می خواهید دسترسی به این داده ها را به گونه ای محدود کنید که فقط کاربر وارد شده بتواند داده های خود را مشاهده کند ، قوانین شما چیزی شبیه به این خواهد بود.

{
  "rules": {
    "users": {
      "$uid": {
        ".read": "auth != null && auth.uid == $uid"
      }
    }
  }
}

کار با ادعاهای سفارشی احراز هویت

برای برنامه های که نیاز به کنترل دسترسی سفارشی برای کاربران مختلف، فایربیس احراز هویت اجازه می دهد تا توسعه دهندگان به ادعاهای مجموعه بر روی یک کاربر فایربیس . این ادعاها قابل دسترسی برای همگان در می auth.token متغیر در قوانین خود را. در اینجا یک مثال از قوانین است که استفاده از است hasEmergencyTowel را سفارشی:

{
  "rules": {
    "frood": {
      // A towel is about the most massively useful thing an interstellar
      // hitchhiker can have
      ".read": "auth.token.hasEmergencyTowel === true"
    }
  }
}

توسعه دهندگان ایجاد خود تأیید اعتبار سفارشی خود اختیاری می توانید ادعا کند که به این نشانه ها اضافه کنید. این ادعاها avaialble در می auth.token متغیر در قوانین خود را.

داده های موجود در مقابل داده های جدید

از پیش تعریف شده data متغیر استفاده شده است برای اشاره به داده ها قبل از یک عملیات نوشتن می گیرد. در مقابل، newData متغیر شامل داده های جدید است که وجود دارد اگر نوشتن از عمل موفقیت آمیز است. newData نشان دهنده نتیجه ادغام شده از داده های جدید در حال نوشته شده و داده های موجود.

برای توضیح ، این قانون به ما اجازه می دهد تا پرونده های جدیدی ایجاد کنیم یا پرونده های موجود را حذف کنیم ، اما در داده های غیر خالی موجود تغییر ایجاد نکنیم:

// we can write as long as old data or new data does not exist
// in other words, if this is a delete or a create, but not an update
".write": "!data.exists() || !newData.exists()"

ارجاع داده ها در سایر مسیرها

هر داده ای می تواند به عنوان معیاری برای قوانین مورد استفاده قرار گیرد. با استفاده از متغیرهای از پیش تعریف شده root ، data ، و newData ، ما می توانید هر مسیر به عنوان آن را قبل یا بعد از یک رویداد ارسال وجود دسترسی داشته باشید.

این مثال، که اجازه می دهد عملیات نوشتن تا زمانی در نظر بگیرید به عنوان ارزش /allow_writes/ گره است true ، گره پدر و مادر یک ندارد readOnly مجموعه پرچم، و یک کودک به نام وجود دارد foo در داده تازه نوشته شده:

".write": "root.child('allow_writes').val() === true &&
          !data.parent().child('readOnly').exists() &&
          newData.child('foo').exists()"

اعتبار سنجی داده ها

اجرای ساختمان داده و اعتبار ساختار و محتوای داده ها باید با استفاده از انجام شود .validate قوانین، که اجرا می شوند تنها پس از یک .write حکومت موفق به اعطای دسترسی. در زیر یک نمونه است .validate زمینه قوانین و مقررات که تنها اجازه می دهد تا تاریخ را به قالب YYYY-MM-DD بین سال های 1900-2099، که با استفاده از یک عبارت منظم بررسی می شود.

".validate": "newData.isString() &&
              newData.val().matches(/^(19|20)[0-9][0-9][-\\/. ](0[1-9]|1[012])[-\\/. ](0[1-9]|[12][0-9]|3[01])$/)"

.validate قوانین تنها نوع حکومت امنیتی که انجام آبشار نیست. در صورت شکست هرگونه قانون اعتبارسنجی در پرونده کودک ، کل عملیات نوشتن رد می شود. علاوه بر این، تعاریف اعتبار نادیده گرفته می شوند که اطلاعات حذف شده است (این است که، زمانی که مقدار جدید در حال نوشته شده است null ).

ممکن است این نکات بی اهمیت به نظر برسند ، اما در واقع ویژگی های مهمی برای نوشتن قوانین امنیتی قدرتمند پایگاه داده Firebase Realtime هستند. قوانین زیر را در نظر بگیرید:

{
  "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()"
      }
    }
  }
}

با در نظر گرفتن این نوع ، نتایج عملیات نوشتن زیر را مشاهده کنید:

جاوا اسکریپت
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);
هدف-ج
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];
سریع
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);
جاوا
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);
باقی مانده
# 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

حالا اجازه دهید نگاه در همان ساختار، اما با استفاده از .write قوانین به جای .validate :

{
  "rules": {
    // this variant will NOT allow deleting records (since .write would be disallowed)
    "widget": {
      // a widget must have 'color' and 'size' in order to be written to this path
      ".write": "newData.hasChildren(['color', 'size'])",
      "size": {
        // the value of "size" must be a number between 0 and 99, ONLY IF WE WRITE DIRECTLY TO SIZE
        ".write": "newData.isNumber() && newData.val() >= 0 && newData.val() <= 99"
      },
      "color": {
        // the value of "color" must exist as a key in our mythical valid_colors/ index
        // BUT ONLY IF WE WRITE DIRECTLY TO COLOR
        ".write": "root.child('valid_colors/'+newData.val()).exists()"
      }
    }
  }
}

در این نوع ، هر یک از عملیات زیر موفق خواهد شد:

جاوا اسکریپت
var ref = new Firebase(URL + "/widget");

// ALLOWED? Even though size is invalid, widget has children color and size,
// so write is allowed and the .write rule under color is ignored
ref.set({size: 99999, color: 'red'});

// ALLOWED? Works even if widget does not exist, allowing us to create a widget
// which is invalid and does not have a valid color.
// (allowed by the write rule under "color")
ref.child('size').set(99);
هدف-ج
Firebase *ref = [[Firebase alloc] initWithUrl:URL];

// ALLOWED? Even though size is invalid, widget has children color and size,
// so write is allowed and the .write rule under color is ignored
[ref setValue: @{ @"size": @9999, @"color": @"red" }];

// ALLOWED? Works even if widget does not exist, allowing us to create a widget
// which is invalid and does not have a valid color.
// (allowed by the write rule under "color")
[[ref childByAppendingPath:@"size"] setValue: @99];
سریع
var ref = Firebase(url:URL)

// ALLOWED? Even though size is invalid, widget has children color and size,
// so write is allowed and the .write rule under color is ignored
ref.setValue(["size": 9999, "color": "red"])

// ALLOWED? Works even if widget does not exist, allowing us to create a widget
// which is invalid and does not have a valid color.
// (allowed by the write rule under "color")
ref.childByAppendingPath("size").setValue(99)
جاوا
Firebase ref = new Firebase(URL + "/widget");

// ALLOWED? Even though size is invalid, widget has children color and size,
// so write is allowed and the .write rule under color is ignored
Map<String,Object> map = new HashMap<String, Object>();
map.put("size", 99999);
map.put("color", "red");
ref.setValue(map);

// ALLOWED? Works even if widget does not exist, allowing us to create a widget
// which is invalid and does not have a valid color.
// (allowed by the write rule under "color")
ref.child("size").setValue(99);
باقی مانده
# ALLOWED? Even though size is invalid, widget has children color and size,
# so write is allowed and the .write rule under color is ignored
curl -X PUT -d '{size: 99999, color: "red"}' \
https://docs-examples.firebaseio.com/rest/securing-data/example.json

# ALLOWED? Works even if widget does not exist, allowing us to create a widget
# which is invalid and does not have a valid color.
# (allowed by the write rule under "color")
curl -X PUT -d '99' \
https://docs-examples.firebaseio.com/rest/securing-data/example/size.json

این نشان می دهد تفاوت های بین .write و .validate قوانین. به عنوان نشان داده، این قوانین باید با استفاده از نوشته شود .validate ، با استثنای از newData.hasChildren() حکومت، که در مورد اینکه آیا حذف باید اجازه داده شود بستگی دارد.

قوانین مبتنی بر پرس و جو

اگر چه شما می توانید قوانین را به عنوان فیلتر استفاده نکنید ، شما می توانید دسترسی به زیر مجموعه ای از داده ها با استفاده از پارامترهای پرس و جو در قوانین خود را محدود می کند. استفاده از query. عباراتی در قوانین شما برای دسترسی به خواندن یا نوشتن بر اساس پارامترهای پرس و جو.

به عنوان مثال، پرس و جو بر اساس قانون پس از استفاده از قوانین امنیتی مبتنی بر کاربر و قوانین مبتنی بر پرس و جو به محدود کردن دسترسی به داده ها در baskets مجموعه به تنها سبدهای خرید کاربر فعال صاحب:

"baskets": {
  ".read": "auth.uid != null &&
            query.orderByChild == 'owner' &&
            query.equalTo == auth.uid" // restrict basket access to owner of basket
}

پرس و جو زیر ، که شامل پارامترهای پرس و جو در قاعده است ، موفق می شود:

db.ref("baskets").orderByChild("owner")
                 .equalTo(auth.currentUser.uid)
                 .on("value", cb)                 // Would succeed

با این حال، نمایش داده شد که پارامترها در قانون عبارتند از: نمی خواهد با یک شکست PermissionDenied خطا:

db.ref("baskets").on("value", cb)                 // Would fail with PermissionDenied

همچنین می توانید از قوانین مبتنی بر پرس و جو برای محدود کردن میزان بارگیری مشتری از طریق عملیات خواندن استفاده کنید.

به عنوان مثال ، قانون زیر دسترسی به خواندن را تنها به 1000 نتیجه اولیه یک پرس و جو محدود می کند ، به ترتیب اولویت:

messages: {
  ".read": "query.orderByKey &&
            query.limitToFirst <= 1000"
}

// Example queries:

db.ref("messages").on("value", cb)                // Would fail with PermissionDenied

db.ref("messages").limitToFirst(1000)
                  .on("value", cb)                // Would succeed (default order by key)

در زیر query. عبارات در قوانین امنیتی پایگاه داده در زمان واقعی موجود است.

عبارات قانون مبتنی بر پرس و جو
اصطلاح تایپ کنید شرح
query.orderByKey
query.orderByPriority
query.orderByValue
بولین برای پرسش های مرتب شده بر اساس کلید ، اولویت یا مقدار درست است. در غیر این صورت غلط است.
query.orderByChild رشته
خالی
از یک رشته برای نشان دادن مسیر نسبی به گره فرزند استفاده کنید. به عنوان مثال، query.orderByChild == "address/zip" . اگر درخواست توسط یک گره فرزند مرتب نشده باشد ، این مقدار تهی است.
query.startAt
query.endAt
query.equalTo
رشته
عدد
بولین
خالی
محدوده پرس و جوی اجرایی را بازیابی می کند ، یا در صورت عدم وجود مجموعه محدود ، null را برمی گرداند.
query.limitToFirst
query.limitToLast
عدد
خالی
محدودیت پرس و جوی اجرایی را بازیابی می کند ، یا در صورت عدم وجود محدودیت ، مقدار null را برمی گرداند.

مراحل بعدی

پس از این بحث شرایط ، شما درک پیچیده تری از قوانین پیدا کرده اید و آماده هستید:

نحوه مدیریت موارد استفاده اصلی را یاد بگیرید و گردش کار برای توسعه ، آزمایش و استقرار قوانین را بیاموزید:

ویژگیهای قوانین مربوط به پایگاه داده Realtime را بیاموزید: