您可以使用 Firebase Security Rules,根據資料庫或儲存體值區中的現有資料,有條件地寫入新資料。您也可以撰寫規則,根據要寫入的新資料限制寫入作業,以便強制執行資料驗證。請繼續閱讀,進一步瞭解如何使用現有資料建立安全性條件。
請在各個部分中選取產品,進一步瞭解資料驗證規則。
新資料的限制
Cloud Firestore
如果您想確保系統不會建立包含特定欄位的文件,可以將該欄位納入 allow
條件。舉例來說,如要拒絕建立任何包含 ranking
欄位的文件,您可以在 create
條件中禁止該欄位。
service cloud.firestore {
match /databases/{database}/documents {
// Disallow
match /cities/{city} {
allow create: if !("ranking" in request.resource.data)
}
}
}
Realtime Database
如要確保不將含有特定值的資料新增至資料庫,請在規則中加入該值,並禁止寫入。舉例來說,如果您想拒絕任何含有 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')
}
}
Cloud Storage
如要確保不會建立包含特定中繼資料的檔案,您可以在 allow
條件中加入中繼資料。舉例來說,如果您想拒絕建立任何含有 ranking
中繼資料的檔案,請在 create
條件中禁止這項操作。
service firebase.storage {
match /b/{bucket}/o {
match /files/{allFiles=**} {
// Disallow
allow create: if !("ranking" in request.resource.metadata)
}
}
}
使用 Firebase Security Rules 中的現有資料
Cloud Firestore
許多應用程式會將存取權控管資訊儲存為資料庫中文件的欄位。Cloud Firestore Security Rules 可根據文件資料動態允許或拒絕存取權:
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;
}
}
}
Realtime Database
在 Realtime Database 中,請使用 .validate
規則強制執行資料結構,並驗證資料的格式和內容。確認 .write
規則已授予存取權後,Rules 就會執行 .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);
Objective-C
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];
Swift
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);
Java
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);
REST
# 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
Cloud Storage
評估規則時,您可能也會想評估要上傳、下載、修改或刪除檔案的中繼資料。這可讓您建立複雜且強大的規則,例如只允許上傳特定內容類型的檔案,或只刪除超過特定大小的檔案。
resource
物件包含鍵/值組合,其中檔案中繼資料會顯示在 Cloud Storage 物件中。您可以在 read
或 write
要求上檢查這些屬性,確保資料完整性。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
物件。如果允許 write
,request.resource
物件會從將要寫入的檔案取得中繼資料。
您可以使用這兩個值來避免不必要或不一致的更新,或是強制應用程式限制,例如檔案類型或大小。
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
物件中的完整屬性清單,請參閱參考說明文件。