Firebase Database Security Rules API

規則:類型

.read

可授予用戶端 Firebase 即時資料庫位置的讀取權限。

.read 規則是一種安全性規則,可授予用戶端 Firebase 即時資料庫位置的讀取權限。例如:

 ".read": "auth != null && auth.provider == 'twitter'"

.read 規則的值是字串,系統會將其評估為 JavaScript 運算式語法的子集,但會進行一些行為變更,以提高清晰度和正確性。授予位置讀取權限的 .read 規則也會允許讀取該位置的所有子系,即使子係有自己的 .read 規則失敗也一樣。

.read 規則可以存取所有 Firebase 即時資料庫的規則變數,但 newData 除外。

.write

可授予用戶端 Firebase 即時資料庫位置的寫入權限。

.write 規則是一種安全性規則,可授予用戶端寫入 Firebase 即時資料庫位置的權限。例如:

".write": "auth != null && auth.token.isAdmin == true"

.write 規則的值是字串,系統會將其評估為 JavaScript 運算式語法的子集,但會進行一些行為變更,以提高清晰度和正確性。授予某位置寫入權限的 .write 規則,也會允許寫入該位置的所有子系,即使子係有自己的 .write 規則而失敗也一樣。

.write 規則可存取所有 Firebase 即時資料庫的規則變數

.validate

.write 規則授予存取權後使用,確保寫入的資料符合特定結構定義。

一旦 .write 規則授予存取權後,就會使用 .validate 規則,確保寫入的資料符合特定標準。除了 .write 會授予存取權,所有相關 .validate 規則都必須成功執行,才能允許寫入。例如:

".validate": "newData.hasChildren(['name', 'age'])"

.validate 規則的值是字串,系統會將其評估為 JavaScript 運算式語法的子集,但會進行一些行為變更,以提高清晰度和正確性。

.validate 規則可存取所有 Firebase 即時資料庫的規則變數

.indexOn

讓 Firebase 即時資料庫瞭解你想將資料編入索引的鍵,藉此提高查詢成效。

.indexOn 規則會指示 Firebase 即時資料庫伺服器為資料中的特定鍵建立索引,藉此提升查詢效能。舉例來說,假設資料庫中有一組恐龍資料,您可以新增下列規則,指示 Firebase 即時資料庫將查詢最佳化,避免伺服器傳回查詢資料:

{
  "rules": {
    "dinosaurs": {
      ".indexOn": ["height", "length"]
    }
  }
}

如要進一步瞭解 .indexOn 規則,請參閱安全性指南中「建立資料索引」一節。

規則:變數

auth

包含權杖酬載的變數 (如果用戶端已通過驗證);或 null

Firebase 即時資料庫可讓您輕鬆向多個內建供應商進行驗證,並為其產生驗證權杖。當使用者透過任一內建供應商完成驗證後,Auth 變數就會包含以下內容:

欄位 說明
provider 使用的驗證方式 (例如「password」、「anonymous」、「facebook」、「github」、「google」或「twitter」)。
uid 不重複的使用者 ID,保證在所有供應商中都不得重複。
token Firebase 驗證 ID 權杖的內容。請參閱 auth.token

舉例來說,我們可以使用下列規則,允許使用者在註解中儲存使用者 ID 時發表留言:

{
  "rules": {
    ".read": true,
    "$comment": {
      ".write": "!data.exists() && newData.child('user_id').val() == auth.uid"
    }
  }
}

我們也可以設定如下的規則,讓使用者只要登入 Facebook 即可留下評論:

{
  "rules": {
    ".read": true,
    "$comment": {
      ".write": "!data.exists() && auth.provider == 'facebook'"
    }
  }
}

auth.token

包含 Firebase 驗證 ID 權杖內容的變數。

權杖包含下列部分或所有鍵:

欄位 說明
email 與帳戶相關聯的電子郵件地址 (如有)。
email_verified 如果使用者已確認他們能使用 email 地址,則請true。部分供應商會自動驗證他們擁有的電子郵件地址。
phone_number 與帳戶相關聯的電話號碼 (如果有的話)。
name 使用者的顯示名稱 (如有設定)。
sub 使用者的 Firebase UID。這個名稱在專案中是獨一無二的。
firebase.identities 與這位使用者帳戶相關聯的所有身分字典。字典金鑰可以是下列任一項目:emailphonegoogle.comfacebook.comgithub.comtwitter.com。字典的值是與帳戶相關聯的每個識別資訊提供者的專屬 ID 陣列。例如,auth.token.firebase.identities["google.com"][0] 包含與帳戶相關聯的第一個 Google 使用者 ID。
firebase.sign_in_provider 用於取得這個權杖的登入提供者。可以是下列任一字串:custompasswordphoneanonymousgoogle.comfacebook.comgithub.comtwitter.com
firebase.tenant 與帳戶相關聯的 LoyaltyId (如有)。例如:tenant2-m6tyz

如果使用自訂驗證,auth.token 也會包含任何自訂驗證 聲明。

這些值都可以在規則中使用。舉例來說,如要限制只能存取與 gmail.com 地址相關聯的 Google 帳戶,我們可以新增以下規則:

{
  "rules": {
    ".read": "auth != null",
    "gmailUsers": {
      "$uid": {
        ".write": "auth.token.email_verified == true && auth.token.email.matches(/.*@gmail.com$/)"
      }
    }
  }
}

為求完整性,auth.token 中也會加入下列欄位,但這些欄位對規則來說不太可能實用。

欄位 說明
iss 權杖的核發者。
aud 權杖的目標對象。
auth_time 使用者上次使用接收權杖的裝置進行憑證驗證的時間。
iat 核發權杖的時間。
exp 權杖的到期時間。

$location

這個變數可用於參照先前在規則結構中使用的 $location 索引鍵。

在規則結構中使用 $location 時,可以在規則運算式中使用相符的 $ 變數,取得要讀取或寫入的實際子項名稱。因此,假設我們要授予每位使用者自己 /users/<user> 位置的讀取和寫入權限。我們可以使用:

{
  "rules": {
    "users": {
      "$user": {
        ".read": "auth.uid === $user",
        ".write": "auth.uid === $user"
      }
    }
  }
}

當用戶端嘗試存取 /users/barney 時,$user 預設位置會與 $user 等於「barney」相同。因此 .read 規則會檢查 auth.uid === 'barney'。因此,只有在用戶端使用「barney」的 uid 進行驗證時,讀取 /users/barney 才會成功。

現在

包含自 Unix 紀元以來的毫秒數 (根據 Firebase 即時資料庫伺服器)。

now 變數包含從 UNIX 紀元以來的毫秒數 (根據 Firebase 即時資料庫伺服器)。舉例來說,您可以利用這項程式碼,確認使用者的 created 時間一律不會設為未來時間:

{
  "rules": {
    "users": {
      "$user": {
        "created": {
          ".validate": "newData.val() < now"
        }
      }
    }
  }
}

root

與 Firebase 即時資料庫根目錄的目前資料相對應的 RuleDataSnapshot

根變數可提供與 Firebase 即時資料庫根目錄的目前資料相對應的 RuleDataSnapshot。方便您在規則運算式中讀取資料庫中的任何資料。舉例來說,如果只想允許使用者在 /users/<id>/active 設為 True 時讀取 /comments,可使用:

{
  "rules": {
    "comments": {
      ".read": "root.child('users').child(auth.uid).child('active').val() == true"
    }
  }
}

然後,如果 /users/barney/active 包含值 true,使用者就會使用「barney」做為 uid 進行驗證寫入「/comments」節點

資料

與目前執行規則所在位置對應的 Firebase 即時資料庫資料相對應的 RuleDataSnapshot

資料變數可提供與目前執行規則中資料庫位置 (而非根層級) 資料對應的 RuleDataSnapshot

舉例來說,如果您想在 /users/<user>/public 設為 True 的情況下,允許任何用戶端存取 /users/<user>,可以使用:

{
  "rules": {
    "users": {
      "$user": {
        ".read": "data.child('public').val() == true"
      }
    }
  }
}

資料變數可在 .read.write.validate 規則。

新資料

如果允許寫入,則與查詢結果相對應的 RuleDataSnapshot

如果是 .write.validate 規則,新的資料變數會提供 RuleDataSnapshot,內容與寫入作業允許時會產生的資料對應 (這是現有資料的「合併」,加上寫入的新資料)。因此,如要確保每位使用者都有名稱和年齡,可以使用:

{
  "rules": {
    "users": {
      "$user": {
        ".read": true,
        ".write": true,
        ".validate": "newData.hasChildren(['name', 'age'])"
      }
    }
  }
}

由於 newData 會合併現有資料和新資料,即使是「部分」資料也能正常執行更新。例如:

var fredRef = firebase.database().ref("users/fred");
// Valid since we have a name and age.
fredRef.set({ name: "Fred", age: 19 });
// Valid since we are updating the name but there's already an age.
fredRef.child("age").set(27);
// Invalid since the .validate rule will no longer be true.
fredRef.child("name").remove();

由於未寫入新資料,因此 .read 規則不提供 newData 變數。請只使用data

RuleDataSnapshot:方法

val()

從這個 RuleDataSnapshot 取得原始值 (stringnumberbooleannull)。

傳回值:(StringNumberBooleanNull) - 這個 RuleDataSnapshot 的原始值。

DataSnapshot.val() 不同,在包含子項資料的 RuleDataSnapshot 上呼叫 val(),不會傳回包含子項的物件。而會改為傳回特殊的密封指示值。這可確保規則一律能以最有效率的方式運作。

因此,您必須一律使用 child() 存取子項 (例如 data.child('name').val(),而非 data.val().name)。

這個範例只有在讀取位置的 isReadable 子項設為 true 時,才會允許讀取。

".read": "data.child('isReadable').val() == true"

子項()

取得指定相對路徑位置的 RuleDataSnapshot

引數childPath String - 子項資料位置的相對路徑。

傳回值RuleDataSnapshot - 子項位置的 RuleDataSnapshot

相對路徑可以是簡單的子項名稱 (例如「fred」),也可以是更深的斜線分隔路徑 (例如「fred/name/first」)。如果子位置沒有資料,則會傳回空白的 RuleDataSnapshot。

這個範例只有在讀取位置的 isReadable 子項設為 true 時,才會允許讀取。

".read": "data.child('isReadable').val() == true"

父項 (父項)

取得父項位置的 RuleDataSnapshot

傳回值RuleDataSnapshot - 父項位置的 RuleDataSnapshot

如果這個執行個體參照 Firebase 即時資料庫的根層級,就表示該執行個體沒有父項,且 parent() 失敗,導致系統略過目前的規則運算式 (失敗時)。

這個範例只有在 isReadable 同層級設為 true 時才會讀取。

".read": "data.parent().child('isReadable').val() == true"

hasChild(childPath)

如果指定的子已存在,則傳回 true。

引數childPath String - 指向潛在子項位置的相對路徑。

傳回值布林值 - true如果指定子路徑有資料,其他 false

這個範例僅允許在含有子項「name」時寫入資料。

".validate": "newData.hasChild('name')"

hasChildren([孩童])

檢查子項是否存在。

引數children Array 選用 - 必須全部存在的子項鍵陣列。

傳回值Boolean - true (如果 (指定) 有子項);其他 false

如果未提供引數,當 RuleDataSnapshot 有任何子項時,會傳回 true。如果提供子項名稱陣列,則只有在 RuleDataSnapshot 中包含所有指定的子項時,才會傳回 true。

這個範例僅允許在含有一或多個子項的資料寫入。

".validate": "newData.hasChildren()"

這個範例只允許寫入含有「name」的資料和「age」。

".validate": "newData.hasChildren(['name', 'age'])"

已存在()

如果這個 RuleDataSnapshot 包含任何資料,則傳回 true。

傳回值Boolean - true (如果 RuleDataSnapshot 包含任何資料);其他為 false

如果這個 RuleDataSnapshot 包含任何資料,存在的函式會傳回 true。由於 data.exists() 等於 data.val() != null,因此這只是便利函式。

本範例允許在沒有現有資料的情況下寫入。

".write": "!data.exists()"

getPriority()

取得 RuleDataSnapshot 中的資料優先順序。

傳回值:(StringNumberNull) - 此 RuleDataSnapshot 中的資料優先順序。

這個範例可確保寫入的新資料具有優先順序

".validate": "newData.getPriority() != null"

isNumber()

如果這個 RuleDataSnapshot 包含數字,則傳回 true。

傳回值Boolean - true (如果資料是數值);其他 false

這個範例可確保寫入的新資料含有子項「age」做為參考依據

".validate": "newData.child('age').isNumber()"

isString()

如果這個 RuleDataSnapshot 包含字串值,則傳回 true。

傳回值Boolean - true 如果資料是 String;反之為 false

這個範例可確保寫入的新資料含有子項「name」子項取代為字串值。

".validate": "newData.child('name').isString()

isBoolean()

如果這個 RuleDataSnapshot 包含布林值,則傳回 true。

傳回值Boolean - true 如果資料是 Boolean;其他 false

這個範例可確保寫入的新資料具有子項「active」替換成布林值

".validate": "newData.child('active').isBoolean()"

字串:屬性

長度

傳回字串長度。

傳回值Number - 字串中的字元數。

這個範例的字串長度至少要有 10 個半形字元。

".validate": "newData.isString() && newData.val().length >= 10"

字串:方法

contains(子字串)

如果字串包含指定子字串,則傳回 true。

引數substring String - 要尋找的子字串。

傳回值Boolean - true (如果字串包含指定的子字串);其他 false

這個範例要求資料必須是包含「@」的字串。

".validate": "newData.isString() && newData.val().contains('@')"

StartWith(子字串)

如果字串開頭為指定子字串,則傳回 true。

引數substring String - 要用於開頭的子字串。

傳回值Boolean - true (如果字串包含指定的子字串);其他 false

以下範例允許在 auth.token.identifier 開頭為「internal-」時允許讀取

".read": "auth.token.identifier.beginsWith('internal-')"

endWith(子字串)

如果字串結尾是指定子字串,則傳回 true。

引數substring String - 要用於尋找結尾的子字串。

傳回值Boolean - true (如果字串結尾是指定子字串);其他 false

這個範例允許讀取權限,如果 auth.token.identifier 結尾是「@company.com」

".read": "auth.token.identifier.endsWith('@company.com')"

replace(子字串, 取代)

傳回包含指定子字串所有例項,以指定取代字串取代的字串副本。

引數substring String - 要尋找的子字串。 replacement String- 要取代子字串的字串。

傳回值String - 以取代子字串取代子字串後的新字串。

replace() 方法與 JavaScript replace() 方法稍有不同,因為它會將指定子字串的所有例項替換成指定的替代字串,而不只是第一個例項。

由於鍵中不允許使用半形句號,因此我們需要在儲存這些字串前,先以半形句號逸出字串。例如電子郵件地址。假設我們在 /whitelist/ 節點中已有許可清單中的電子郵件地址:

{
 "user": {
   "$uid": {
     "email": <email>
   }
 },
 "whitelist": {
   "fred@gmail%2Ecom": true,
   "barney@aol%2Ecom": true
 }
}

我們可以建立規則,規定使用者的電子郵件地址必須位於 /whitelist/ 節點中:

{
  "rules": {
    "users": {
      "$uid": {
        ".read": "true",
        ".write": "root.child('whitelist').child(newData.child('email').val().replace('.', '%2E')).exists()"
      }
    }
  }
}

toLowerCase()

傳回轉換為小寫字串的副本。

傳回值String - 轉換為小寫的字串。

本範例允許讀取權限,因為 auth.token.identifier 全都存在於 /users 下。

".read": "root.child('users').child(auth.token.identifier.toLowerCase()).exists()"

toUpperCase()

傳回將字串轉換成大寫的字串。

傳回值String - 轉換為大寫的字串。

以下範例允許讀取,如果 auth.token.identifier 全都位於 /users 底下,就允許讀取。

".read": "root.child('users').child(auth.token.identifier.toUpperCase()).exists()"

match(規則運算式)

如果字串與指定的規則運算式常值相符,則會傳回 true。

傳回值Boolean - true 如果字串與規則運算式常值「regex」相符;其他 false

請參閱規則規則運算式說明文件

運算子

+ (新增)

用於新增變數或字串串連。

以下範例可確保新值只會將現有值遞增 1。這有助於實作計數器:

".write": "newData.val() === data.val() + 1"
".validate": "root.child('room_names/' + $room_id).exists()"

- (否定或減去)

用於在規則運算式中否定值或減去兩個值。

這項驗證規則會檢查這個新值是位置的子項值相反值:

".validate": "newData.val() === -(data.child('quantity').val())"

以下範例使用減號,確保系統只會讀取過去 10 分鐘內的郵件:

".read": "newData.child('timestamp').val() > (now - 600000)"

* (乘號)

用來將規則運算式中的變數相乘。

這項驗證規則會檢查新值是否等於價格和數量的產物 (兩個現有的值):

".validate": "newData.val() === data.child('price').val() * data.child('quantity').val()"

/ (除號)

用於在規則運算式中劃分變數。

在以下範例中,驗證規則可確保儲存的資料是其他位置儲存的總資料平均值:

".validate": "newData.val() === data.parent().child('sum').val() / data.parent().child('numItems').val()"

% (模數)

用來尋找規則運算式中將一個變數除以另一個變數的餘數。

這項規則會驗證只能寫入偶數:

".validate": "newData.val() % 2 === 0"

=== (等於)

用來檢查規則運算式中兩個變數的類型和值是否相同。

以下規則使用 === 運算子,僅將寫入存取權授予使用者帳戶的擁有者。使用者的 UID 必須與鍵 ($user_id) 完全相符,規則才會判定為 true。

"users": {
  ".write": "$user_id === auth.uid"
}

!== (不等於)

用來檢查規則運算式中的兩個變數是否相等。

下列讀取規則可確保只有登入的使用者可以讀取資料:

".read": "auth !== null"

(&&)(和)

如果兩個運算元都為 true,就會傳回 True。用來評估規則運算式中的多個條件。

以下驗證規則會檢查新的資料是少於 100 個字元的字串:

".validate": "newData.isString() && newData.val().length < 100"

||(或)

如果規則運算式中的一個運算元為 true,就會傳回 TRUE。

在此範例中,只要舊資料不存在或沒有新資料,我們即可寫入。也就是說,當刪除或建立資料後,我們不會更新資料,而是可以撰寫。

".write": "!data.exists() || !newData.exists()"

!(否)

如果單一運算元為 false,則傳回 True。在規則運算式中,!運算子通常用於確認資料是否已寫入位置。

以下規則僅允許在指定位置沒有資料的情況下寫入:

".write": "!data.exists()"

> (大於)

用於檢查某個值是否大於規則運算式中的另一個值。

這項驗證規則會檢查所寫入的字串並非空白字串:

".validate": "newData.isString() && newData.val().length > 0"

< (小於)

用於檢查某個值是否小於規則運算式中的值。

這項驗證規則會檢查字串是否少於 20 個半形字元:

".validate": "newData.isString() && newData.val().length < 20"

>= (大於或等於)

用來檢查某個值是否大於或等於規則運算式中的另一個值。

這項驗證規則會檢查所寫入的字串並非空白字串:

".validate": "newData.isString() && newData.val().length >= 1"

<= (小於或等於)

用於檢查某個值是否小於或等於規則運算式中的其他值。

這項驗證規則可確保日後無法加入新資料:

".validate": "newData.val() <= now"

?(三元運算子)

用於評估條件規則運算式。

三元運算子會使用三個運算元。?做為條件如果條件評估為 true,則會評估第二個運算元。如果條件為 False,則會評估第三個運算元。

下列驗證規則的新值可以是數字或布林值。如果這是數字,則必須大於 0。

".validate": "newData.isNumber() ? newData.val() > 0 : newData.isBoolean()"