了解 2023 年 Google I/O 大会上介绍的 Firebase 亮点。了解详情

數據驗證

您可以使用 Firebase 安全規則根據數據庫或存儲桶中的現有數據有條件地寫入新數據。您還可以編寫規則,通過根據正在寫入的新數據限制寫入來強制執行數據驗證。繼續閱讀以了解有關使用現有數據創建安全條件的規則的更多信息。

在每個部分中選擇一個產品以了解有關數據驗證規則的更多信息。

對新數據的限制

雲端 Firestore

如果您想確保不創建包含特定字段的文檔,您可以在allow條件中包含該字段。例如,如果您想拒絕創建任何包含ranking字段的文檔,您可以在create條件中禁止它。

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

實時數據庫

如果您想確保包含某些值的數據不會添加到您的數據庫中,您可以將該值包含在您的規則中並禁止它進行寫入。例如,如果您想拒絕任何包含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')
    }
  }

雲儲存

如果您想確保不創建包含特定元數據的文件,您可以在allow條件中包含元數據。例如,如果您想拒絕創建任何包含ranking數據的文件,您可以在create條件中禁止它。

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

使用 Firebase 安全規則中的現有數據

雲端 Firestore

許多應用程序將訪問控制信息存儲為數據庫中文檔的字段。 Cloud Firestore 安全規則可以根據文檔數據動態允許或拒絕訪問:

  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變量的更多信息,請參閱參考文檔

寫入數據時,您可能希望將傳入數據與現有數據進行比較。這使您可以執行一些操作,例如確保字段未更改、字段僅遞增 1,或者新值至少在未來一周後出現。在這種情況下,如果您的規則集允許掛起的寫入,則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;
      }
    }
  }

實時數據庫

在實時數據庫中,使用.validate規則來強制執行數據結構並驗證數據的格式和內容。規則在驗證.write規則授予訪問權限後運行.validate規則。

.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);
目標-C
注意:此 Firebase 產品不適用於 App Clip 目標。
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];
迅速
注意:此 Firebase 產品不適用於 App Clip 目標。
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

雲儲存

在評估規則時,您可能還想評估正在上傳、下載、修改或刪除的文件的元數據。這使您可以創建複雜而強大的規則,例如只允許上傳具有特定內容類型的文件,或者只允許刪除大於特定大小的文件。

resource對象包含鍵/值對,文件元數據顯示在 Cloud Storage 對像中。可以在readwrite請求時檢查這些屬性以確保數據完整性。 resource對象檢查 Cloud Storage 存儲桶中現有文件的元數據。

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

您還可以在write請求(例如上傳、元數據更新和刪除)上使用request.resource對象。如果允許寫入, request.resource對象會從將要write的文件中獲取元數據。

您可以使用這兩個值來防止不需要的或不一致的更新或強制執行應用程序約束,例如文件類型或大小。

  service firebase.storage {
    match /b/{bucket}/o {
      match /images {
        // Cascade read to any image type at any path
        match /{allImages=**} {
          allow read;
        }

        // 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) File name (stored in imageId wildcard variable) is less than 32 characters
        match /{imageId} {
          allow write: if request.resource.size < 5 * 1024 * 1024
                       && request.resource.contentType.matches('image/.*')
                       && request.resource.contentType == resource.contentType
                       && imageId.size() < 32
        }
      }
    }
  }

參考文檔中提供了resource對像中的完整屬性列表。