阻止用户更改Firestore中特定文档字段的问题

时间:2018-11-14 13:55:53

标签: firebase google-cloud-firestore google-cloud-functions firebase-security-rules

我在Android项目中使用firebase,我在Cloud Firestore数据库中有一个用户集合,用户只能更新某些字段,但可以读取所有字段,我知道无法保护文档的一部分进行了更新,并且安全规则只能应用于整个文档,因此我进行了搜索,发现的唯一解决方案是在用户文档中创建一个子集合,并在该子集合中创建一个新文档,最后将其放入我想在其中保护的字段,然后我可以在安全规则部分中应用以下代码轻松保护此文档:

match /users/{userId}/securedData/{securedData} {
  allow write: if false;
  allow read: if true;
}

所以现在没有人可以写这些字段,但是任何人都可以阅读,而这正是我想要的,但是后来我发现我需要根据子集合内的字段(称为集合)来查询用户。群组查询目前尚不支持,因此我得到了两种解决方案:

  1. 检索所有用户并在客户端对其进行过滤,但这将增加读取文档的数量,因为我要查询所有用户的集合文档+为每个用户读取的额外子集合文档,以获得所需的字段过滤用户。
  2. 与其在用户文档中建立子集合并引起这些问题,不如将所有字段保留在顶层文档(用户文档)中,从而允许用户更新任何字段。

    match /users/{userId} {
      allow update, read: if true;
      allow create, remove: if false;
    }
    

    但是创建一个(onUpdate)云函数来监听用户文档的更新和 检测用户不允许修改的字段中的更改,因此 如果用户尝试更改这些字段,则可以检测到该错误并将修改后的字段恢复为以前的值,如下所示:

    export const updateUser = functions.firestore
        .document('users/{userId}')
        .onUpdate((change, context) => {
            const previousValue = change.before.data().securedField;
            const newValue = change.after.data().securedField;
    
            if (previousValue !== newValue) {
                return db.collection('users')
                    .doc(context.params.userId)
                    .update({ securedField: previousValue });
            }
        });
    

第二种解决方案安全吗?哪个是最好的解决方案?或任何其他解决方案?

1 个答案:

答案 0 :(得分:2)

您的方法肯定是可能的,并且是对Cloud Functions的有趣使用。但是,从用户进行写操作到Cloud Function检测到并还原更改之间会有一段时间。

我可能会在安全规则中遇到这种情况。虽然您不能拒绝用户在安全规则中写入字段,但您可以 确保用户只能向当前具有相同字段的字段写入相同的值。这实际上也使他们无法更改字段的值。您可以通过以下方式做到这一点:

allow write: if request.resource.data.securedField == resource.data.securedField;

此规则确保更新文档(request.resource.data.securedField)中的字段与当前文档(resource.data.securedField)中的字段具有相同的值。