mdi*_*ker 3 firebase-security google-cloud-firestore
tl;dr:我认为Set需要一种方法来获取元素 ( set.toList()[0]),但也许我错过了一些东西!
你好!我正在开发一个预算应用程序,使用 Firestore 和大量小对象(信用卡交易)。为了限制读取次数,将每个事务存储为单独的文档是没有意义的,因为用户可能一次需要数百个事务。
相反,我有一个容器来保存许多交易,如下所示:
/user/{user_id}/transactions/{container_id}
container: {
transactions: {
transaction_id_1: {
amount: 8.25,
note: 'chipotle lunch'
},
transaction_id_2: {
amount: 12.01
}
}
}
Run Code Online (Sandbox Code Playgroud)
这很好用,但我认为安全规则不适用于写入。我希望允许用户修改某些字段 ( note),但不允许修改其他字段 ( amount)。如果每个事务都是一个文档,我们可以使用MapDiff来完成此操作,但嵌套使其变得更加困难。
由于我们无法编写 for 循环,因此如果我们将自己限制为每次写入一个更新的事务,那么使用嵌套的 MapDiff 应该完全可以实现这一点,如下所示:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents/{document=**} {
function allowTransactionUpdate() {
let transactionId = <transaction ID of the single transaction being updated>;
// Limit fields updated for container.
return request.resource.data.diff(resource.data).changedKeys()
.hasOnly(['transactions']) &&
// Make sure only one transaction changed.
request.resource.data.transactions.diff(resource.data.transactions)
.changedKeys().hasOnly([transactionId]) &&
// Verify the transaction already exists.
transactionId in resource.data.transactions &&
// Only allow certain fields to be updated on that transaction.
request.resource.data.transactions[transactionId]
.diff(resource.data.transactions[transactionId]).affectedKeys()
.hasOnly(['note']);
}
match /transactions/{transMonthId} {
allow update: if allowTransactionWrite();
}
allow read, write: if false;
}
}
Run Code Online (Sandbox Code Playgroud)
如果我们可以使用 MapDiff 来获取 Map 中发生更改的事务,这将非常有效container.transactions:
let transactionId = request.resource.data.transactions
.diff(resource.data.transactions).changedKeys()[0];
Run Code Online (Sandbox Code Playgroud)
关键缺失的部分是最后一位:[0]。目前,Set无法获取元素,这意味着将某些内容转换为 Set(以及使用 MapDiff 的任何内容)是一个死胡同:您实际上无法知道 Set 中的值是什么。它只能与其他套装进行比较。
否则……我是不是错过了什么?是否有另一种方法来限制嵌套更新的字段?
其他选项是:
对于正在寻找嵌套对象和 MapDiff 示例的其他人
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
function affectedKeys(keys){
return request.resource.data.diff(resource.data).affectedKeys().hasOnly(keys)
}
function affectedKeysObj(obj1Key, obj2Key, keys){
return request.resource.data[obj1Key].diff(resource.data[obj2Key]).affectedKeys().hasOnly(keys)
}
match /{document=**} {
allow read, write: if false;
}
match /users/{uid}{
allow get: if request.auth.uid == uid;
allow update: if request.auth.uid == uid
&& ! affectedKeys(["meta"])
&& affectedKeys(["userData"])
&& affectedKeysObj("userData", "userData", ["bio", "displayName"]);
}
}
}
Run Code Online (Sandbox Code Playgroud)
在本例中,我希望用户能够在地图["bio", "displayName"]内进行编辑userData,但我也希望禁止编辑地图meta。
然而,关于这个问题,Doug Stevensons 是对的,我只是补充说,这就是我将 MapDiff 与嵌套对象一起使用的方式。
| 归档时间: |
|
| 查看次数: |
875 次 |
| 最近记录: |