你可以透過 Firebase 即時資料庫安全性規則,控管已儲存資料的存取權 資料庫內的項目彈性規則語法可讓您建立 從所有寫入資料庫到作業等任何條件 安排在個別節點上執行
即時資料庫安全性規則是資料庫的「宣告」設定。也就是說 規則與產品邏輯分開定義。這個 有許多好處:客戶不需負責強制執行安全措施,而錯誤 不會損害您的資料,最重要的是 就算沒有中繼推薦人 (例如伺服器),也能妥善保護資料 。
本主題說明基本的語法和即時資料庫安全性規則結構 以便建立完整規則集
建立安全性規則
即時資料庫安全性規則是由類似 JavaScript 的運算式組成,包含在 JSON 文件。您的規則結構必須遵循 儲存在資料庫中的資料
基本規則識別一組要保護的節點,也就是存取方法 (例如讀取、
寫入權限,以及允許或拒絕存取的條件。
在以下範例中,條件是簡單的 true
,
false
陳述式,但下一個主題將介紹更多的動態方式
則明確條件。
舉例來說,如要嘗試保護 parent_node
下的 child_node
,
常用的語法如下:
{ "rules": { "parent_node": { "child_node": { ".read": <condition>, ".write": <condition>, ".validate": <condition>, } } } }
接著套用這個模式舉例來說,假設您正在追蹤某份清單 ,而且資料看起來會像這樣:
{ "messages": { "message0": { "content": "Hello", "timestamp": 1405704370369 }, "message1": { "content": "Goodbye", "timestamp": 1405704395231 }, ... } }
您的規則結構必須相似。這個是 可能適合這個資料結構的唯讀安全性規則。這個 範例會示範如何指定要套用規則的資料庫節點 也就是評估這些節點規則的條件
{ "rules": { // For requests to access the 'messages' node... "messages": { // ...and the individual wildcarded 'message' nodes beneath // (we'll cover wildcarding variables more a bit later).... "$message": { // For each message, allow a read operation if <condition>. In this // case, we specify our condition as "true", so read access is always granted. ".read": "true", // For read-only behavior, we specify that for write operations, our // condition is false. ".write": "false" } } } }
基本規則作業
強制執行安全性的規則分為三種類型
對資料執行的作業:.write
、.read
和 .validate
。這裡
簡短摘要說明這些用途:
規則類型 | |
---|---|
.read | 說明使用者是否可以讀取資料,以及何時允許讀取資料。 |
.write | 說明是否允許寫入資料,以及何時可以寫入資料。 |
.validate | 定義格式正確的值會呈現的樣子 (無論是否有錯誤) 含有子屬性和資料類型 |
萬用字元擷取變數
所有規則陳述式都指向節點。陳述可以指向特定的
節點或使用 $
萬用字元擷取變數,指向位於
階層層級使用這些擷取變數來儲存節點的值
鍵。這項技術可讓您
較複雜的 Rules 條件,我們稍後將進一步說明
下一個主題
{ "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 } } } }
讀取及寫入規則串聯
.read
和 .write
規則由上而下運作,採用淺層次模式
通常會覆寫更深層的規則如果有規則授予特定資料的讀取或寫入權限
路徑,也可以授予存取權
其下的所有子節點請參考以下結構:
{ "rules": { "foo": { // allows read to /foo/* ".read": "data.child('baz').val() === true", "bar": { /* ignored, since read was allowed already */ ".read": false } } } }
這個安全性結構允許 /bar/
讀取
/foo/
包含具有 true
值的子項 baz
。
/foo/bar/
下的 ".read": false
規則沒有任何
因為子項路徑無法撤銷存取權。
雖然看起來可能不太直覺,但這是規則用語的重要一環 並提供非常複雜的存取權限,可輕鬆實作。這個 。
請注意,.validate
規則不會串聯。所有驗證規則
都必須滿足階層的所有層級,才能允許寫入。
規則不是篩選器
規則會以整體化的方式套用。也就是說 如果該位置沒有規則,作業就會立即失敗 授予存取權限的上層位置。即使每個受影響的子項路徑都可以存取 導致無法完整讀取請參考以下結構:
{ "rules": { "records": { "rec1": { ".read": true }, "rec2": { ".read": false } } } }
如果不瞭解規則會以不可分割的形式進行評估
擷取 /records/
路徑時,將傳回 rec1
但不含 rec2
。不過,實際結果會是錯誤:
JavaScript
var db = firebase.database(); db.ref("records").once("value", function(snap) { // success method is not called }, function(err) { // error callback triggered with PERMISSION_DENIED });
Objective-C
FIRDatabaseReference *ref = [[FIRDatabase database] reference]; [[_ref child:@"records"] observeSingleEventOfType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) { // success block is not called } withCancelBlock:^(NSError * _Nonnull error) { // cancel block triggered with PERMISSION_DENIED }];
Swift
var ref = FIRDatabase.database().reference() ref.child("records").observeSingleEventOfType(.Value, withBlock: { snapshot in // success block is not called }, withCancelBlock: { error in // cancel block triggered with PERMISSION_DENIED })
Java
FirebaseDatabase database = FirebaseDatabase.getInstance(); DatabaseReference ref = database.getReference("records"); ref.addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(DataSnapshot snapshot) { // success method is not called } @Override public void onCancelled(FirebaseError firebaseError) { // error callback triggered with PERMISSION_DENIED }); });
REST
curl https://docs-examples.firebaseio.com/rest/records/ # response returns a PERMISSION_DENIED error
由於 /records/
的讀取作業是不可分割的,因此沒有
讀取規則,用於授予 /records/
下所有資料的存取權,
這會產生 PERMISSION_DENIED
錯誤如果我們評估
只要前往 Firebase 控制台的安全模擬工具輸入規則,即可看到
讀取作業遭拒,因為沒有讀取規則允許存取
/records/
路徑。但請注意,rec1
的規則
由於該連結不在我們要求的路徑中,因此未評估。擷取
rec1
,我們需要直接存取:
JavaScript
var db = firebase.database(); db.ref("records/rec1").once("value", function(snap) { // SUCCESS! }, function(err) { // error callback is not called });
Objective-C
FIRDatabaseReference *ref = [[FIRDatabase database] reference]; [[ref child:@"records/rec1"] observeSingleEventOfType:FEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) { // SUCCESS! }];
Swift
var ref = FIRDatabase.database().reference() ref.child("records/rec1").observeSingleEventOfType(.Value, withBlock: { snapshot in // SUCCESS! })
Java
FirebaseDatabase database = FirebaseDatabase.getInstance(); DatabaseReference ref = database.getReference("records/rec1"); ref.addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(DataSnapshot snapshot) { // SUCCESS! } @Override public void onCancelled(FirebaseError firebaseError) { // error callback is not called } });
REST
curl https://docs-examples.firebaseio.com/rest/records/rec1 # SUCCESS!
重疊聲明
您可以為節點套用多項規則,在
如果有多個規則運算式識別節點,存取方法則是
如有任一條件為 false
,就會拒絕:
{ "rules": { "messages": { // A rule expression that applies to all nodes in the 'messages' node "$message": { ".read": "true", ".write": "true" }, // A second rule expression applying specifically to the 'message1` node "message1": { ".read": "false", ".write": "false" } } } }
在上述範例中,對於 message1
節點的讀取作業會是
遭到拒絕,因為第二個規則一律為 false
,即使第一個規則
則一律為 true
。
後續步驟
歡迎進一步瞭解 Firebase 即時資料庫安全性規則:
瞭解 Rules 語言的下一個主要概念:動態 條件,可讓 Rules 檢查使用者 授權、比較現有資料和傳入資料、驗證傳入資料、 查詢來自用戶端的查詢結構等等
查看一般安全性用途,以及解決這些需求的 Firebase 安全性規則定義。