英文:
Multiple field validation in Firebase Firestore security rules
问题
I have written the following security rule for the GameAdmins collection of my Firestore database:
match /GameAdmins/{adminId} {
function validAdminData() {
let keys = request.resource.data.keys().toSet();
let allowedKeys = ['admin', 'superAdmin'].toSet();
let data = request.resource.data;
return (keys == allowedKeys) && (data.admin is bool) && (data.superAdmin is bool);
}
allow create, update: if isSuperAdmin() && validAdminData();
allow delete: if isSuperAdmin();
}
So it allows only two boolean fields admin and superAdmin while creating or updating a document. This method was easy to write since it has only two fields. It gets difficult when I want to write the same method for a different collection that has a lot of fields since I would have to write the list of keys and check the type of each field.
I thought of keeping dummy data in the database so that I can get the list of allowed keys from there. But I still have to check each of their types separately.
Is there a better way to check the list of keys and their types with less amount of codes?
英文:
I have written the following security rule for the GameAdmins collection of my Firestore database:
match /GameAdmins/{adminId} {
function validAdminData() {
let keys = request.resource.data.keys().toSet();
let allowedKeys = ['admin', 'superAdmin'].toSet();
let data = request.resource.data;
return (keys == allowedKeys) && (data.admin is bool) && (data.superAdmin is bool);
}
allow create, update: if isSuperAdmin() && validAdminData();
allow delete: if isSuperAdmin();
}
So it allows only two boolean fields admin and superAdmin while creating or updating a document. This method was easy to write since it has only two fields. It gets difficult when I want to write the same method for a different collection that has a lot of fields since I would have to write the list of keys and check the type of each field.
I thought of keeping dummy data in the database so that I can get the list of allowed keys from there. But I still have to check each of their types separately.
Is there a better way to check the list of keys and their types with less amount of codes?
答案1
得分: 1
我写了一些功能,它们虽然不是完全动态的,但目前可以使用。
function validateType(data, type) {
return (
(type == 'string' && data is string) ||
(type == 'int' && data is int) ||
(type == 'bool' && data is bool) ||
(type == 'timestamp' && data is timestamp) ||
(type == 'list' && data is list)
);
}
function validateEachField(data, model) {
let keys = model.keys();
let n = keys.size() - 1;
return (
(n <= 0 || validateType(data[keys[0]], model[keys[0]])) &&
(n <= 1 || validateType(data[keys[1]], model[keys[1])) &&
(n <= 2 || validateType(data[keys[2]], model[keys[2])) &&
(n <= 3 || validateType(data[keys[3]], model[keys[3])) &&
(n <= 4 || validateType(data[keys[4]], model[keys[4])) &&
(n <= 5 || validateType(data[keys[5]], model[keys[5])) &&
(n <= 6 || validateType(data[keys[6]], model[keys[6])) &&
(n <= 7 || validateType(data[keys[7]], model[keys[7])) &&
(n <= 8 || validateType(data[keys[8]], model[keys[8])) &&
(n <= 9 || validateType(data[keys[9]], model[keys[9]))
);
}
function validateData(collection) {
let model = get(/databases/$(database)/documents/DataModels/$(collection)/$(collection)).data;
let keys = request.resource.data.keys().toSet();
let allowedKeys = model.keys().toSet();
return keys == allowedKeys && validateEachField(request.resource.data, model);
}
唯一的问题似乎是当字段数量增加时,可能需要在 validateEachField 函数中添加更多行,以及在未来为 validateType 函数添加更多类型的支持。
英文:
I wrote some functions that are not completely dynamic but work for now.
function validateType(data, type) {
return (
(type == 'string' && data is string) ||
(type == 'int' && data is int) ||
(type == 'bool' && data is bool) ||
(type == 'timestamp' && data is timestamp) ||
(type == 'list' && data is list)
);
}
function validateEachField(data, model) {
let keys = model.keys();
let n = keys.size() - 1;
return (
(n <= 0 || validateType(data[keys[0]], model[keys[0]])) &&
(n <= 1 || validateType(data[keys[1]], model[keys[1]])) &&
(n <= 2 || validateType(data[keys[2]], model[keys[2]])) &&
(n <= 3 || validateType(data[keys[3]], model[keys[3]])) &&
(n <= 4 || validateType(data[keys[4]], model[keys[4]])) &&
(n <= 5 || validateType(data[keys[5]], model[keys[5]])) &&
(n <= 6 || validateType(data[keys[6]], model[keys[6]])) &&
(n <= 7 || validateType(data[keys[7]], model[keys[7]])) &&
(n <= 8 || validateType(data[keys[8]], model[keys[8]])) &&
(n <= 9 || validateType(data[keys[9]], model[keys[9]]))
);
}
function validateData(collection) {
let model = get(/databases/$(database)/documents/DataModels/$(collection)/$(collection)).data;
let keys = request.resource.data.keys().toSet();
let allowedKeys = model.keys().toSet();
return keys == allowedKeys && validateEachField(request.resource.data, model);
}
The only problem seems to be I might have to add more lines in the validateEachField function when the number of fields increases and add support for more types in the validateType function in the future.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论