Firebase Security Rules از زبانهای منعطف، قدرتمند و سفارشی استفاده میکند که از طیف وسیعی از پیچیدگی و جزئیات پشتیبانی میکنند. شما می توانید Rules خود را به همان اندازه که برای برنامه شما منطقی است، خاص یا عمومی کنید. قوانین Realtime Database از نحوی استفاده می کنند که شبیه جاوا اسکریپت در ساختار JSON است. قواعد Cloud Firestore و Cloud Storage از زبانی مبتنی بر Common Expression Language (CEL) استفاده میکنند که بر روی CEL با match
ایجاد میکند و به عباراتی allow
که از دسترسی مشروط اعطا شده پشتیبانی میکنند.
از آنجایی که این زبانها زبانهای سفارشی هستند، اما منحنی یادگیری وجود دارد. از این راهنما برای درک بهتر زبان Rules استفاده کنید، زیرا در قوانین پیچیدهتر عمیقتر میشوید.
یک محصول را انتخاب کنید تا در مورد قوانین آن بیشتر بدانید.
ساختار اساسی
Cloud Firestore
Firebase Security Rules در Cloud Firestore و Cloud Storage از ساختار و نحو زیر استفاده می کنند:
service <<name>> {
// Match the resource path.
match <<path>> {
// Allow the request if the following conditions are true.
allow <<methods>> : if <<condition>>
}
}
مفاهیم کلیدی زیر هنگام ایجاد قوانین برای درک مهم هستند:
- Request: متد یا متدهای فراخوانی شده در دستور
allow
. اینها روشهایی هستند که شما به آنها اجازه اجرا می دهید. روش های استاندارد عبارتند از:get
،list
،create
،update
وdelete
. روشهای راحتread
وwrite
، دسترسی گسترده خواندن و نوشتن را در پایگاه داده یا مسیر ذخیرهسازی مشخص شده امکانپذیر میسازد. - Path: پایگاه داده یا محل ذخیره سازی که به عنوان یک مسیر URI نشان داده می شود.
- قانون: عبارت
allow
، که شامل شرطی است که در صورت ارزیابی صحیح، به درخواست اجازه می دهد.
هر یک از این مفاهیم در ادامه با جزئیات بیشتر توضیح داده شده است.
Cloud Storage
Firebase Security Rules در Cloud Firestore و Cloud Storage از ساختار و نحو زیر استفاده می کنند:
service <<name>> {
// Match the resource path.
match <<path>> {
// Allow the request if the following conditions are true.
allow <<methods>> : if <<condition>>
}
}
مفاهیم کلیدی زیر هنگام ایجاد قوانین برای درک مهم هستند:
- Request: متد یا متدهای فراخوانی شده در دستور
allow
. اینها روشهایی هستند که شما به آنها اجازه اجرا می دهید. روش های استاندارد عبارتند از:get
،list
،create
،update
وdelete
. روشهای راحتread
وwrite
، دسترسی گسترده خواندن و نوشتن را در پایگاه داده یا مسیر ذخیرهسازی مشخص شده امکانپذیر میسازد. - Path: پایگاه داده یا محل ذخیره سازی که به عنوان یک مسیر URI نشان داده می شود.
- قانون: عبارت
allow
، که شامل شرطی است که در صورت ارزیابی صحیح، به درخواست اجازه می دهد.
هر یک از این مفاهیم در ادامه با جزئیات بیشتر توضیح داده شده است.
Realtime Database
در Realtime Database ، Firebase Security Rules از عبارات جاوا اسکریپت مانند موجود در یک سند JSON تشکیل شده است.
آنها از نحو زیر استفاده می کنند:
{
"rules": {
"<<path>>": {
// Allow the request if the condition for each method is true.
".read": <<condition>>,
".write": <<condition>>,
".validate": <<condition>>
}
}
}
سه عنصر اساسی در قانون وجود دارد:
- مسیر: محل پایگاه داده. این ساختار JSON پایگاه داده شما را منعکس می کند.
- درخواست: اینها روش هایی هستند که قانون برای اعطای دسترسی استفاده می کند. قوانین
read
وwrite
، دسترسی خواندن و نوشتن گسترده ای را اعطا می کنند، در حالی که قوانینvalidate
به عنوان یک تأیید ثانویه برای اعطای دسترسی بر اساس داده های ورودی یا موجود عمل می کنند. - شرط: شرطی که به یک درخواست اجازه می دهد در صورتی که درست ارزیابی شود.
ساختارهای قانون
Cloud Firestore
عناصر اساسی یک قانون در Cloud Firestore و Cloud Storage به شرح زیر است:
- اعلامیه
service
: محصول Firebase را که قوانین بر آن اعمال می شود، اعلام می کند. - بلوک
match
: مسیری را در پایگاه داده یا سطل ذخیره سازی که قوانین روی آن اعمال می شود، تعریف می کند. - عبارت
allow
: شرایطی را برای اعطای دسترسی فراهم می کند که بر اساس روش ها متمایز می شود. روش های پشتیبانی شده عبارتند از:get
،list
،create
،update
،delete
، و روش های آسانread
وwrite
. - اعلان های
function
اختیاری: امکان ترکیب و بسته بندی شرایط را برای استفاده در چندین قانون فراهم می کند.
این service
حاوی یک یا چند بلوک match
با دستورات allow
که شرایطی را برای دسترسی به درخواست ها فراهم می کند. متغیرهای request
و resource
برای استفاده در شرایط قانون در دسترس هستند. زبان Firebase Security Rules نیز از اعلانهای function
پشتیبانی میکند.
نسخه نحوی
دستور syntax
نشان دهنده نسخه زبان قوانین Firebase است که برای نوشتن منبع استفاده شده است. آخرین نسخه این زبان v2
است.
rules_version = '2';
service cloud.firestore {
...
}
اگر هیچ عبارت rules_version
ارائه نشده باشد، قوانین شما با استفاده از موتور v1
ارزیابی خواهند شد.
خدمات
اعلامیه service
مشخص می کند که قوانین شما در مورد کدام محصول یا خدمات Firebase اعمال می شود. شما فقط می توانید یک اعلان service
در هر فایل منبع اضافه کنید.
Cloud Firestore
service cloud.firestore {
// Your 'match' blocks with their corresponding 'allow' statements and
// optional 'function' declarations are contained here
}
Cloud Storage
service firebase.storage {
// Your 'match' blocks with their corresponding 'allow' statements and
// optional 'function' declarations are contained here
}
اگر قوانینی را برای Cloud Firestore و Cloud Storage با استفاده از Firebase CLI تعریف می کنید، باید آنها را در فایل های جداگانه نگهداری کنید.
مطابقت دادن
یک بلوک match
الگوی path
را اعلام میکند که با مسیر عملیات درخواستی مطابقت دارد (مسیر request.path
ورودی). بدنه match
باید یک یا چند بلوک match
تودرتو، عبارات allow
یا اعلان function
داشته باشد. مسیر در بلوکهای match
تودرتو نسبت به مسیر بلوک match
والد است.
الگوی path
یک نام دایرکتوری است که ممکن است متغییرها یا حروف عام باشد. الگوی path
امکان تطابق بخش تک مسیری و بخش چند مسیری را فراهم می کند. هر متغیر محدود شده در یک path
در محدوده match
یا هر محدوده تودرتو که در آن path
اعلام شده است قابل مشاهده است.
مطابقت با الگوی path
ممکن است جزئی یا کامل باشد:
- منطبقات جزئی: الگوی
path
پیشوندی ازrequest.path
است. - تطابق کامل: الگوی
path
با کلrequest.path
مطابقت دارد.
هنگامی که یک تطابق کامل ایجاد می شود، قوانین درون بلوک ارزیابی می شوند. وقتی یک تطابق جزئی ایجاد میشود، قوانین match
تودرتو آزمایش میشوند تا ببینند آیا path
تودرتو تطابق را کامل میکند یا خیر.
قوانین در هر match
کامل برای تعیین اینکه آیا درخواست مجاز است یا خیر ارزیابی می شود. اگر قانون منطبق اجازه دسترسی را بدهد، درخواست مجاز است. اگر هیچ قانون منطبقی اجازه دسترسی را نداد، درخواست رد می شود.
// Given request.path == /example/hello/nested/path the following
// declarations indicate whether they are a partial or complete match and
// the value of any variables visible within the scope.
service firebase.storage {
// Partial match.
match /example/{singleSegment} { // `singleSegment` == 'hello'
allow write; // Write rule not evaluated.
// Complete match.
match /nested/path { // `singleSegment` visible in scope.
allow read; // Read rule is evaluated.
}
}
// Complete match.
match /example/{multiSegment=**} { // `multiSegment` == /hello/nested/path
allow read; // Read rule is evaluated.
}
}
همانطور که مثال بالا نشان می دهد، اعلان path
از متغیرهای زیر پشتیبانی می کند:
- علامت عام تک بخش: یک متغیر علامت عام در یک مسیر با قرار دادن یک متغیر در پرانتزهای فرفری اعلام می شود:
{variable}
. این متغیر در دستورmatch
به عنوان یکstring
قابل دسترسی است. - عام بازگشتی: عام بازگشتی، یا چند بخش، بخش های مسیر متعدد را در یک مسیر یا زیر آن مطابقت می دهد. این علامت عام با همه مسیرهای زیر مکانی که آن را تنظیم کرده اید مطابقت دارد. می توانید آن را با افزودن رشته
=**
در انتهای متغیر بخش خود اعلام کنید:{variable=**}
. این متغیر در دستورmatch
به عنوان یک شیpath
قابل دسترسی است.
اجازه دهید
بلوک match
حاوی یک یا چند عبارت allow
. اینها قوانین واقعی شما هستند. می توانید قوانین allow
را برای یک یا چند روش اعمال کنید. برای اینکه Cloud Firestore یا Cloud Storage برای اعطای هر درخواست دریافتی، شرایط یک عبارت allow
را درست ارزیابی کند. همچنین می توانید عبارات allow
را بدون شرط بنویسید، به عنوان مثال، allow read
. با این حال، اگر دستور allow
شامل یک شرط نباشد، همیشه درخواست آن متد را مجاز میکند.
اگر هر یک از قوانین allow
برای روش برآورده شود، درخواست مجاز است. بهعلاوه، اگر قانون گستردهتری اجازه دسترسی را بدهد، Rules دسترسی را اعطا میکنند و هر قانون جزئی دیگری را که ممکن است دسترسی را محدود کند نادیده میگیرد.
مثال زیر را در نظر بگیرید، جایی که هر کاربر می تواند هر یک از فایل های خود را بخواند یا حذف کند. یک قانون جزئی تر فقط در صورتی اجازه نوشتن را می دهد که کاربر درخواست کننده نوشتن مالک فایل باشد و فایل PNG باشد. کاربر میتواند هر فایلی را در مسیر فرعی حذف کند - حتی اگر PNG نباشد - زیرا قانون قبلی این اجازه را میدهد.
service firebase.storage {
// Allow the requestor to read or delete any resource on a path under the
// user directory.
match /users/{userId}/{anyUserFile=**} {
allow read, delete: if request.auth != null && request.auth.uid == userId;
}
// Allow the requestor to create or update their own images.
// When 'request.method' == 'delete' this rule and the one matching
// any path under the user directory would both match and the `delete`
// would be permitted.
match /users/{userId}/images/{imageId} {
// Whether to permit the request depends on the logical OR of all
// matched rules. This means that even if this rule did not explicitly
// allow the 'delete' the earlier rule would have.
allow write: if request.auth != null && request.auth.uid == userId && imageId.matches('*.png');
}
}
روش
هر دستور allow
شامل روشی است که به درخواست های ورودی همان روش دسترسی می دهد.
روش | نوع درخواست |
---|---|
روش های راحتی | |
read | هر نوع درخواست خواندن |
write | هر نوع درخواست نوشتن |
روش های استاندارد | |
get | درخواستها برای اسناد یا فایلهای واحد را بخوانید |
list | درخواستهای مربوط به پرسشها و مجموعهها را بخوانید |
create | اسناد یا فایل های جدید بنویسید |
update | در اسناد پایگاه داده موجود بنویسید یا ابرداده فایل را به روز کنید |
delete | داده ها را حذف کنید |
نمیتوانید روشهای خواندن را در یک بلوک match
یا روشهای نوشتن متناقض در یک اعلان path
همپوشانی کنید.
به عنوان مثال، قوانین زیر شکست خواهند خورد:
service bad.example {
match /rules/with/overlapping/methods {
// This rule allows reads to all authenticated users
allow read: if request.auth != null;
match another/subpath {
// This secondary, more specific read rule causes an error
allow get: if request.auth != null && request.auth.uid == "me";
// Overlapping write methods in the same path cause an error as well
allow write: if request.auth != null;
allow create: if request.auth != null && request.auth.uid == "me";
}
}
}
تابع
همانطور که قوانین امنیتی شما پیچیدهتر میشوند، ممکن است بخواهید مجموعهای از شرایط را در توابعی بپیچید که بتوانید در سراسر مجموعه قوانین خود دوباره از آنها استفاده کنید. قوانین امنیتی از توابع سفارشی پشتیبانی می کنند. سینتکس توابع سفارشی کمی شبیه جاوا اسکریپت است، اما توابع قوانین امنیتی در یک زبان مخصوص دامنه نوشته شده اند که دارای محدودیت های مهمی است:
- توابع می توانند تنها حاوی یک عبارت
return
باشند. آنها نمی توانند حاوی هیچ منطق اضافی باشند. به عنوان مثال، آنها نمی توانند حلقه ها را اجرا کنند یا خدمات خارجی را فراخوانی کنند. - توابع می توانند به طور خودکار به توابع و متغیرها از محدوده ای که در آن تعریف شده اند دسترسی داشته باشند. به عنوان مثال، یک تابع تعریف شده در محدوده
service cloud.firestore
به متغیرresource
و توابع داخلی مانندget()
وexists()
دسترسی دارد. - توابع ممکن است توابع دیگر را فراخوانی کنند اما ممکن است تکرار نشوند. کل عمق پشته تماس به 20 محدود شده است.
- در قوانین نسخه
v2
، توابع می توانند متغیرها را با استفاده از کلمه کلیدیlet
تعریف کنند. توابع می توانند حداکثر 10 اتصال let داشته باشند، اما باید با یک عبارت return پایان یابند.
یک تابع با کلمه کلیدی function
تعریف می شود و صفر یا بیشتر آرگومان می گیرد. برای مثال، ممکن است بخواهید دو نوع شرط استفاده شده در مثال های بالا را در یک تابع واحد ترکیب کنید:
service cloud.firestore {
match /databases/{database}/documents {
// True if the user is signed in or the requested data is 'public'
function signedInOrPublic() {
return request.auth.uid != null || resource.data.visibility == 'public';
}
match /cities/{city} {
allow read, write: if signedInOrPublic();
}
match /users/{user} {
allow read, write: if signedInOrPublic();
}
}
}
در اینجا مثالی است که آرگومان های تابع و تخصیص اجازه را نشان می دهد. اجازه دهید دستورات تکلیف باید با نیمه ویرگول از هم جدا شوند.
function isAuthorOrAdmin(userId, article) {
let isAuthor = article.author == userId;
let isAdmin = exists(/databases/$(database)/documents/admins/$(userId));
return isAuthor || isAdmin;
}
توجه داشته باشید که چگونه تخصیص isAdmin
جستجوی مجموعه مدیران را اعمال می کند. برای ارزیابی تنبل بدون نیاز به جستجوهای غیر ضروری، از ماهیت اتصال کوتاه &&
(AND) و ||
استفاده کنید. (OR) مقایسه برای فراخوانی تابع دوم تنها در صورتی که isAuthor
درست (برای مقایسه &&
) یا نادرست (برای مقایسه ||
) نشان داده شود.
function isAdmin(userId) {
return exists(/databases/$(database)/documents/admins/$(userId));
}
function isAuthorOrAdmin(userId, article) {
let isAuthor = article.author == userId;
// `||` is short-circuiting; isAdmin called only if isAuthor == false.
return isAuthor || isAdmin(userId);
}
استفاده از توابع در قوانین امنیتی شما با افزایش پیچیدگی قوانین شما، آنها را قابل نگهداری تر می کند.
Cloud Storage
عناصر اساسی یک قانون در Cloud Firestore و Cloud Storage به شرح زیر است:
- اعلامیه
service
: محصول Firebase را که قوانین بر آن اعمال می شود، اعلام می کند. - بلوک
match
: مسیری را در پایگاه داده یا سطل ذخیره سازی که قوانین روی آن اعمال می شود، تعریف می کند. - عبارت
allow
: شرایطی را برای اعطای دسترسی فراهم می کند که بر اساس روش ها متمایز می شود. روش های پشتیبانی شده عبارتند از:get
،list
،create
،update
،delete
، و روش های آسانread
وwrite
. - اعلان های
function
اختیاری: امکان ترکیب و بسته بندی شرایط را برای استفاده در چندین قانون فراهم می کند.
این service
حاوی یک یا چند بلوک match
با دستورات allow
که شرایط دسترسی به درخواستها را فراهم میکند. متغیرهای request
و resource
برای استفاده در شرایط قانون در دسترس هستند. زبان Firebase Security Rules نیز از اعلانهای function
پشتیبانی میکند.
نسخه نحوی
دستور syntax
نشان دهنده نسخه زبان قوانین Firebase است که برای نوشتن منبع استفاده شده است. آخرین نسخه این زبان v2
است.
rules_version = '2';
service cloud.firestore {
...
}
اگر هیچ عبارت rules_version
ارائه نشده باشد، قوانین شما با استفاده از موتور v1
ارزیابی خواهند شد.
خدمات
اعلامیه service
مشخص می کند که قوانین شما در مورد کدام محصول یا خدمات Firebase اعمال می شود. شما فقط می توانید یک اعلان service
در هر فایل منبع اضافه کنید.
Cloud Firestore
service cloud.firestore {
// Your 'match' blocks with their corresponding 'allow' statements and
// optional 'function' declarations are contained here
}
Cloud Storage
service firebase.storage {
// Your 'match' blocks with their corresponding 'allow' statements and
// optional 'function' declarations are contained here
}
اگر قوانینی را برای Cloud Firestore و Cloud Storage با استفاده از Firebase CLI تعریف می کنید، باید آنها را در فایل های جداگانه نگهداری کنید.
مطابقت دادن
یک بلوک match
الگوی path
را اعلام میکند که با مسیر عملیات درخواستی مطابقت دارد (مسیر request.path
ورودی). بدنه match
باید دارای یک یا چند بلوک match
در تو، عبارات allow
یا اعلان function
باشد. مسیر در بلوک های match
تودرتو نسبت به مسیر در بلوک match
والد است.
الگوی path
یک نام دایرکتوری است که ممکن است متغییرها یا حروف عام باشد. الگوی path
امکان تطابق بخش تک مسیری و بخش چند مسیری را فراهم می کند. هر متغیر محدود شده در یک path
در محدوده match
یا هر محدوده تودرتو که در آن path
اعلام شده است قابل مشاهده است.
مطابقت با الگوی path
ممکن است جزئی یا کامل باشد:
- منطبقات جزئی: الگوی
path
پیشوندی ازrequest.path
است. - تطابق کامل: الگوی
path
با کلrequest.path
مطابقت دارد.
هنگامی که یک تطابق کامل ایجاد می شود، قوانین درون بلوک ارزیابی می شوند. وقتی یک تطابق جزئی ایجاد میشود، قوانین match
تودرتو آزمایش میشوند تا ببینند آیا path
تودرتو تطابق را کامل میکند یا خیر.
قوانین در هر match
کامل برای تعیین اینکه آیا درخواست مجاز است یا خیر ارزیابی می شود. اگر قانون منطبق اجازه دسترسی را بدهد، درخواست مجاز است. اگر هیچ قانون منطبقی اجازه دسترسی را نداد، درخواست رد می شود.
// Given request.path == /example/hello/nested/path the following
// declarations indicate whether they are a partial or complete match and
// the value of any variables visible within the scope.
service firebase.storage {
// Partial match.
match /example/{singleSegment} { // `singleSegment` == 'hello'
allow write; // Write rule not evaluated.
// Complete match.
match /nested/path { // `singleSegment` visible in scope.
allow read; // Read rule is evaluated.
}
}
// Complete match.
match /example/{multiSegment=**} { // `multiSegment` == /hello/nested/path
allow read; // Read rule is evaluated.
}
}
همانطور که مثال بالا نشان می دهد، اعلان های path
از متغیرهای زیر پشتیبانی می کنند:
- علامت عام تک بخش: یک متغیر عام در یک مسیر با قرار دادن یک متغیر در پرانتزهای فرفری اعلام می شود:
{variable}
. این متغیر در دستورmatch
به عنوان یکstring
قابل دسترسی است. - عام بازگشتی: عام بازگشتی، یا چند بخش، بخش های مسیر متعدد را در یک مسیر یا زیر آن مطابقت می دهد. این حروف عام با همه مسیرهای زیر مکانی که آن را تنظیم کرده اید مطابقت دارد. می توانید آن را با اضافه کردن رشته
=**
در انتهای متغیر بخش خود اعلام کنید:{variable=**}
. این متغیر در دستورmatch
به عنوان یک شیpath
قابل دسترسی است.
اجازه دهید
بلوک match
حاوی یک یا چند عبارت allow
. اینها قوانین واقعی شما هستند. می توانید قوانین allow
را برای یک یا چند روش اعمال کنید. شرایط موجود در بیانیه allow
باید برای Cloud Firestore یا Cloud Storage برای اعطای هر درخواست ورودی به درستی ارزیابی شود. همچنین می توانید عبارات allow
را بدون شرط بنویسید، به عنوان مثال، allow read
. با این حال، اگر دستور allow
شامل یک شرط نباشد، همیشه درخواست آن متد را مجاز میکند.
اگر هر یک از قوانین allow
برای روش برآورده شود، درخواست مجاز است. بهعلاوه، اگر قانون گستردهتری اجازه دسترسی را بدهد، Rules دسترسی را اعطا میکنند و هر قانون جزئی دیگری را که ممکن است دسترسی را محدود کند نادیده میگیرد.
مثال زیر را در نظر بگیرید، جایی که هر کاربر می تواند هر یک از فایل های خود را بخواند یا حذف کند. یک قانون جزئی تر فقط در صورتی اجازه نوشتن را می دهد که کاربر درخواست کننده نوشتن مالک فایل باشد و فایل PNG باشد. کاربر میتواند هر فایلی را در مسیر فرعی حذف کند - حتی اگر PNG نباشد - زیرا قانون قبلی این اجازه را میدهد.
service firebase.storage {
// Allow the requestor to read or delete any resource on a path under the
// user directory.
match /users/{userId}/{anyUserFile=**} {
allow read, delete: if request.auth != null && request.auth.uid == userId;
}
// Allow the requestor to create or update their own images.
// When 'request.method' == 'delete' this rule and the one matching
// any path under the user directory would both match and the `delete`
// would be permitted.
match /users/{userId}/images/{imageId} {
// Whether to permit the request depends on the logical OR of all
// matched rules. This means that even if this rule did not explicitly
// allow the 'delete' the earlier rule would have.
allow write: if request.auth != null && request.auth.uid == userId && imageId.matches('*.png');
}
}
روش
هر دستور allow
شامل روشی است که به درخواست های ورودی همان روش دسترسی می دهد.
روش | نوع درخواست |
---|---|
روش های راحتی | |
read | هر نوع درخواست خواندن |
write | هر نوع درخواست نوشتن |
روش های استاندارد | |
get | درخواستها برای اسناد یا فایلهای واحد را بخوانید |
list | درخواستهای مربوط به پرسشها و مجموعهها را بخوانید |
create | اسناد یا فایل های جدید بنویسید |
update | در اسناد پایگاه داده موجود بنویسید یا ابرداده فایل را به روز کنید |
delete | داده ها را حذف کنید |
نمیتوانید روشهای خواندن را در یک بلوک match
یا روشهای نوشتن متناقض در یک اعلان path
همپوشانی کنید.
به عنوان مثال، قوانین زیر شکست خواهند خورد:
service bad.example {
match /rules/with/overlapping/methods {
// This rule allows reads to all authenticated users
allow read: if request.auth != null;
match another/subpath {
// This secondary, more specific read rule causes an error
allow get: if request.auth != null && request.auth.uid == "me";
// Overlapping write methods in the same path cause an error as well
allow write: if request.auth != null;
allow create: if request.auth != null && request.auth.uid == "me";
}
}
}
تابع
همانطور که قوانین امنیتی شما پیچیدهتر میشوند، ممکن است بخواهید مجموعهای از شرایط را در توابعی بپیچید که بتوانید در سراسر مجموعه قوانین خود دوباره از آنها استفاده کنید. قوانین امنیتی از توابع سفارشی پشتیبانی می کنند. سینتکس توابع سفارشی کمی شبیه جاوا اسکریپت است، اما توابع قوانین امنیتی در یک زبان مخصوص دامنه نوشته شده اند که دارای محدودیت های مهمی است:
- توابع می توانند تنها حاوی یک عبارت
return
باشند. آنها نمی توانند حاوی هیچ منطق اضافی باشند. به عنوان مثال، آنها نمی توانند حلقه ها را اجرا کنند یا خدمات خارجی را فراخوانی کنند. - توابع می توانند به طور خودکار به توابع و متغیرها از محدوده ای که در آن تعریف شده اند دسترسی داشته باشند. به عنوان مثال، یک تابع تعریف شده در محدوده
service cloud.firestore
به متغیرresource
و توابع داخلی مانندget()
وexists()
دسترسی دارد. - توابع ممکن است توابع دیگر را فراخوانی کنند اما ممکن است تکرار نشوند. کل عمق پشته تماس به 20 محدود شده است.
- در قوانین نسخه
v2
، توابع می توانند متغیرها را با استفاده از کلمه کلیدیlet
تعریف کنند. توابع می توانند حداکثر 10 اتصال let داشته باشند، اما باید با یک عبارت return پایان یابند.
یک تابع با کلمه کلیدی function
تعریف می شود و صفر یا بیشتر آرگومان می گیرد. برای مثال، ممکن است بخواهید دو نوع شرط استفاده شده در مثال های بالا را در یک تابع واحد ترکیب کنید:
service cloud.firestore {
match /databases/{database}/documents {
// True if the user is signed in or the requested data is 'public'
function signedInOrPublic() {
return request.auth.uid != null || resource.data.visibility == 'public';
}
match /cities/{city} {
allow read, write: if signedInOrPublic();
}
match /users/{user} {
allow read, write: if signedInOrPublic();
}
}
}
در اینجا مثالی است که آرگومان های تابع و تخصیص اجازه را نشان می دهد. اجازه دهید دستورات تکلیف باید با نیمه ویرگول از هم جدا شوند.
function isAuthorOrAdmin(userId, article) {
let isAuthor = article.author == userId;
let isAdmin = exists(/databases/$(database)/documents/admins/$(userId));
return isAuthor || isAdmin;
}
توجه داشته باشید که چگونه تخصیص isAdmin
جستجوی مجموعه مدیران را اعمال می کند. برای ارزیابی تنبل بدون نیاز به جستجوهای غیر ضروری، از ماهیت اتصال کوتاه &&
(AND) و ||
استفاده کنید. (OR) مقایسه برای فراخوانی تابع دوم تنها در صورتی که isAuthor
درست (برای مقایسه &&
) یا نادرست (برای مقایسه ||
) نشان داده شود.
function isAdmin(userId) {
return exists(/databases/$(database)/documents/admins/$(userId));
}
function isAuthorOrAdmin(userId, article) {
let isAuthor = article.author == userId;
// `||` is short-circuiting; isAdmin called only if isAuthor == false.
return isAuthor || isAdmin(userId);
}
استفاده از توابع در قوانین امنیتی شما با افزایش پیچیدگی قوانین شما، آنها را قابل نگهداری تر می کند.
Realtime Database
همانطور که در بالا ذکر شد، Rules Realtime Database شامل سه عنصر اساسی است: مکان پایگاه داده به عنوان آینه ساختار JSON پایگاه داده، نوع درخواست، و شرایط اعطای دسترسی.
مکان پایگاه داده
ساختار قوانین شما باید از ساختار داده هایی که در پایگاه داده خود ذخیره کرده اید پیروی کند. به عنوان مثال، در یک برنامه چت با لیستی از پیامها، ممکن است دادههایی به شکل زیر داشته باشید:
{
"messages": {
"message0": {
"content": "Hello",
"timestamp": 1405704370369
},
"message1": {
"content": "Goodbye",
"timestamp": 1405704395231
},
...
}
}
قوانین شما باید آن ساختار را منعکس کند. به عنوان مثال:
{
"rules": {
"messages": {
"$message": {
// only messages from the last ten minutes can be read
".read": "data.child('timestamp').val() > (now - 600000)",
// new messages must have a string content and a number timestamp
".validate": "newData.hasChildren(['content', 'timestamp']) &&
newData.child('content').isString() &&
newData.child('timestamp').isNumber()"
}
}
}
}
همانطور که مثال بالا نشان می دهد، Rules Realtime Database از یک متغیر $location
برای مطابقت با بخش های مسیر پشتیبانی می کنند. از پیشوند $
در جلوی بخش مسیر خود استفاده کنید تا قانون خود را با گره های فرزند در طول مسیر مطابقت دهید.
{
"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')"
}
}
}
}
}
همچنین می توانید از $variable
به صورت موازی با نام مسیرهای ثابت استفاده کنید.
{
"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 }
}
}
}
روش
در Realtime Database ، سه نوع قانون وجود دارد. دو نوع از این قوانین - read
و write
- در روش درخواست ورودی اعمال می شود. نوع قانون validate
ساختارهای داده را اعمال می کند و قالب و محتوای داده ها را تأیید می کند. Rules پس از تأیید اینکه یک قانون .write
اجازه دسترسی می دهد، قوانین .validate
اجرا می کنند.
انواع قوانین | |
---|---|
.بخوانید | توضیح می دهد که آیا و چه زمانی داده ها مجاز به خواندن توسط کاربران هستند. |
.نوشتن | توضیح می دهد که آیا و چه زمانی داده ها مجاز به نوشتن هستند. |
اعتبار سنجی | تعیین می کند که یک مقدار به درستی قالب بندی شده چگونه به نظر می رسد، آیا دارای ویژگی های فرزند و نوع داده است. |
به طور پیشفرض، اگر قانونی وجود نداشته باشد، دسترسی به یک مسیر رد میشود.
شرایط ساختمان
Cloud Firestore
شرط یک عبارت بولی است که تعیین می کند آیا یک عملیات خاص باید مجاز یا رد شود. متغیرهای request
و resource
زمینه را برای آن شرایط فراهم می کنند.
متغیر request
متغیر request
شامل فیلدهای زیر و اطلاعات مربوطه است:
request.auth
یک رمز وب JSON (JWT) که حاوی اعتبارنامههای احراز هویت از Firebase Authentication است. نشانه auth
شامل مجموعه ای از ادعاهای استاندارد و هرگونه ادعای سفارشی است که از طریق Firebase Authentication ایجاد می کنید. درباره Firebase Security Rules و Authentication بیشتر بیاموزید.
request.method
روش request.method
ممکن است یکی از روش های استاندارد یا یک روش سفارشی باشد. روشهای راحت read
و write
نیز برای ساده کردن قوانین نوشتن وجود دارد که به ترتیب برای همه روشهای استاندارد فقط خواندنی یا فقط نوشتنی اعمال میشوند.
request.params
request.params
شامل هر داده ای است که به طور خاص به request.resource
مربوط نمی شود و ممکن است برای ارزیابی مفید باشد. در عمل، این نقشه باید برای همه روشهای استاندارد خالی باشد و باید حاوی دادههای غیرمنبعی برای روشهای سفارشی باشد. سرویسها باید مراقب باشند که هیچ یک از کلیدها و مقادیر ارائهشده بهعنوان پارامترها را تغییر نام یا تغییر ندهند.
request.path
request.path
مسیر resource
هدف است. مسیر نسبت به سرویس است. بخشهای مسیر حاوی نویسههای غیر url ایمن مانند /
با URL کدگذاری میشوند.
متغیر resource
resource
مقدار فعلی در سرویس است که به صورت نقشه جفت های کلید-مقدار نمایش داده می شود. ارجاع resource
در یک شرط منجر به حداکثر یک خواندن مقدار از سرویس می شود. این جستجو در هر سهمیه مربوط به خدمات برای منبع حساب می شود. برای get
درخواستها، resource
فقط برای رد کردن سهمیه حساب میکند.
اپراتورها و تقدم عملگر
از جدول زیر به عنوان مرجع برای اپراتورها و اولویت مربوط به آنها در Rules برای Cloud Firestore و Cloud Storage استفاده کنید.
عبارات دلخواه a
و b
، یک فیلد f
و یک شاخص i
داده می شود.
اپراتور | توضیحات | انجمنی |
---|---|---|
a[i] a() af | فهرست، تماس، دسترسی به میدان | چپ به راست | !a -a | نفی واحد | راست به چپ |
a/ba%ba*b | عملگرهای ضربی | چپ به راست |
a+b ab | اپراتورهای افزودنی | چپ به راست |
a>ba>=ba | عملگرهای رابطه ای | چپ به راست |
a in b | وجود در فهرست یا نقشه | چپ به راست |
a is type | مقایسه نوع، که در آن type می تواند bool، int، float، عدد، رشته، لیست، نقشه، مهر زمانی، مدت زمان، مسیر یا latlng باشد. | چپ به راست |
a==ba!=b | عملگرهای مقایسه | چپ به راست | a && b | AND مشروط | چپ به راست |
a || b | OR مشروط | چپ به راست |
a ? true_value : false_value | بیان سه تایی | چپ به راست |
Cloud Storage
شرط یک عبارت بولی است که تعیین می کند آیا یک عملیات خاص باید مجاز یا رد شود. متغیرهای request
و resource
زمینه را برای آن شرایط فراهم می کنند.
متغیر request
متغیر request
شامل فیلدهای زیر و اطلاعات مربوطه است:
request.auth
یک رمز وب JSON (JWT) که حاوی اعتبارنامههای احراز هویت از Firebase Authentication است. نشانه auth
شامل مجموعه ای از ادعاهای استاندارد و هرگونه ادعای سفارشی است که از طریق Firebase Authentication ایجاد می کنید. درباره Firebase Security Rules و Authentication بیشتر بیاموزید.
request.method
روش request.method
ممکن است یکی از روش های استاندارد یا یک روش سفارشی باشد. روشهای راحت read
و write
نیز برای ساده کردن قوانین نوشتن وجود دارد که به ترتیب برای همه روشهای استاندارد فقط خواندنی یا فقط نوشتنی اعمال میشوند.
request.params
request.params
شامل هر داده ای است که به طور خاص به request.resource
مربوط نمی شود و ممکن است برای ارزیابی مفید باشد. در عمل، این نقشه باید برای همه روشهای استاندارد خالی باشد و باید حاوی دادههای غیرمنبعی برای روشهای سفارشی باشد. سرویسها باید مراقب باشند که هیچ یک از کلیدها و مقادیر ارائهشده بهعنوان پارامترها را تغییر نام یا تغییر ندهند.
request.path
request.path
مسیر resource
هدف است. مسیر نسبت به سرویس است. بخشهای مسیر حاوی نویسههای غیر url ایمن مانند /
با URL کدگذاری میشوند.
متغیر resource
resource
مقدار فعلی در سرویس است که به صورت نقشه جفت های کلید-مقدار نمایش داده می شود. ارجاع resource
در یک شرط منجر به حداکثر یک خواندن مقدار از سرویس می شود. این جستجو در هر سهمیه مربوط به خدمات برای منبع حساب می شود. برای get
درخواستها، resource
فقط برای رد کردن سهمیه حساب میکند.
اپراتورها و تقدم عملگر
از جدول زیر به عنوان مرجع برای اپراتورها و اولویت مربوط به آنها در Rules برای Cloud Firestore و Cloud Storage استفاده کنید.
عبارات دلخواه a
و b
، یک فیلد f
و یک شاخص i
داده می شود.
اپراتور | توضیحات | انجمنی |
---|---|---|
a[i] a() af | فهرست، تماس، دسترسی به میدان | چپ به راست | !a -a | نفی واحد | راست به چپ |
a/ba%ba*b | عملگرهای ضربی | چپ به راست |
a+b ab | اپراتورهای افزودنی | چپ به راست |
a>ba>=ba | عملگرهای رابطه ای | چپ به راست |
a in b | وجود در فهرست یا نقشه | چپ به راست |
a is type | مقایسه نوع، که در آن type می تواند bool، int، float، عدد، رشته، لیست، نقشه، مهر زمانی، مدت زمان، مسیر یا latlng باشد. | چپ به راست |
a==ba!=b | عملگرهای مقایسه | چپ به راست | a && b | AND مشروط | چپ به راست |
a || b | OR مشروط | چپ به راست |
a ? true_value : false_value | بیان سه تایی | چپ به راست |
Realtime Database
شرط یک عبارت بولی است که تعیین می کند آیا یک عملیات خاص باید مجاز یا رد شود. شما می توانید آن شرایط را در Rules Realtime Database به روش های زیر تعریف کنید.
متغیرهای از پیش تعریف شده
تعدادی متغیر مفید و از پیش تعریف شده وجود دارد که در داخل یک تعریف قانون می توان به آنها دسترسی داشت. در اینجا خلاصه ای از هر یک آمده است:
متغیرهای از پیش تعریف شده | |
---|---|
اکنون | زمان کنونی بر حسب میلی ثانیه از دوران لینوکس. این به ویژه برای اعتبارسنجی مهرهای زمانی ایجاد شده با firebase.database.ServerValue.TIMESTAMP SDK خوب عمل می کند. |
ریشه | یک RuleDataSnapshot نشان دهنده مسیر ریشه در پایگاه داده Firebase همانطور که قبل از عملیات تلاش شده وجود دارد. |
داده های جدید | یک RuleDataSnapshot که دادهها را به شکلی که پس از عملیات تلاش شده وجود دارد، نشان میدهد. این شامل داده های جدید نوشته شده و داده های موجود است. |
داده ها | یک RuleDataSnapshot که دادهها را بهصورتی که قبل از عملیات انجام شده وجود داشت نشان میدهد. |
متغیرهای $ | یک مسیر عام که برای نمایش شناسه ها و کلیدهای فرزند پویا استفاده می شود. |
اعتبار | نشان دهنده بار توکن کاربر تأیید شده است. |
این متغیرها در هر جایی از قوانین شما قابل استفاده هستند. به عنوان مثال، قوانین امنیتی زیر تضمین می کند که داده های نوشته شده در گره /foo/
باید رشته ای کمتر از 100 کاراکتر باشد:
{ "rules": { "foo": { // /foo is readable by the world ".read": true, // /foo is writable by the world ".write": true, // data written to /foo must be a string less than 100 characters ".validate": "newData.isString() && newData.val().length < 100" } } }
قوانین مبتنی بر داده
هر داده ای در پایگاه داده شما می تواند در قوانین شما استفاده شود. با استفاده از متغیرهای از پیش تعریف شده root
، data
و newData
، می توانید به هر مسیری که قبل یا بعد از یک رویداد نوشتن وجود دارد دسترسی داشته باشید.
این مثال را در نظر بگیرید، که تا زمانی که مقدار گره /allow_writes/
true
است، عملیات نوشتن اجازه می دهد، گره والد یک مجموعه پرچم readOnly
ندارد و فرزندی به نام foo
در داده های جدید نوشته شده وجود دارد:
".write": "root.child('allow_writes').val() === true && !data.parent().child('readOnly').exists() && newData.child('foo').exists()"
قوانین مبتنی بر پرس و جو
اگرچه نمی توانید از قوانین به عنوان فیلتر استفاده کنید، اما می توانید با استفاده از پارامترهای پرس و جو در قوانین خود دسترسی به زیر مجموعه های داده را محدود کنید. از 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.
عبارات در Realtime Database Security Rules در دسترس هستند.
عبارات قانون مبتنی بر پرس و جو | ||
---|---|---|
بیان | تایپ کنید | توضیحات |
query.orderByKey query.orderByPriority query.orderByValue | بولی | درست برای جستارهای مرتب شده بر اساس کلید، اولویت یا مقدار. در غیر این صورت نادرست است. |
query.orderByChild | رشته تهی | از یک رشته برای نشان دادن مسیر نسبی به یک گره فرزند استفاده کنید. برای مثال query.orderByChild === "address/zip" . اگر پرس و جو توسط یک گره فرزند مرتب نشده باشد، این مقدار null است. |
query.startAt query.endAt query.equalTo | رشته شماره بولی تهی | محدودههای کوئری اجرا را بازیابی میکند، یا اگر مجموعهای از کران وجود نداشته باشد، null را برمیگرداند. |
query.limitToFirst query.limitToLast | شماره تهی | محدودیت پرس و جو در حال اجرا را بازیابی می کند یا اگر محدودیتی تنظیم نشده باشد، null را برمی گرداند. |
اپراتورها
Rules Realtime Database از تعدادی عملگر پشتیبانی می کند که می توانید از آنها برای ترکیب متغیرها در عبارت شرط استفاده کنید. لیست کامل اپراتورها را در مستندات مرجع مشاهده کنید.
ایجاد شرایط
شرایط واقعی شما بر اساس دسترسیهایی که میخواهید اعطا کنید، متفاوت خواهد بود. Rules به طور عمدی درجه بسیار زیادی از انعطاف پذیری را ارائه می دهند، بنابراین قوانین برنامه شما می توانند در نهایت به همان اندازه که شما نیاز دارید ساده یا پیچیده باشند.
برای راهنمایی در ایجاد Rules ساده و آماده برای تولید، به قوانین اساسی امنیت مراجعه کنید.