Firestore安全规则-如何检查字段是否已被修改? [英] Firestore Security Rules - How can I check that a field is/isn't being modified?

查看:57
本文介绍了Firestore安全规则-如何检查字段是否已被修改?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我生命中,我无法理解为什么以下内容会导致允许允许写入的false.假设我的users集合开始时是空的,并且我正在从Angular前端编写以下形式的文档:

For the life of me, I cannot understand why the following is resulting in a false for allowing writes. Assume my users collection is empty to start, and I am writing a document of the following form from my Angular frontend:

{
  displayName: 'FooBar',
  email: 'foo.bar@example.com'
}

我当前的安全规则:

service cloud.firestore {
  match /databases/{database}/documents {
    match /users/{userId} {
      function isAdmin() {
        return resource.data.role == 'ADMIN';
      }

      function isEditingRole() {
        return request.resource.data.role != null;
      }

      function isEditingOwnRole() {
        return isOwnDocument() && isEditingRole();
      }

      function isOwnDocument() {
        return request.auth.uid == userId;
      }

      allow read: if isOwnDocument() || isAdmin();
      allow write: if !isEditingOwnRole() && (isOwnDocument() || isAdmin());
    }
  }
}

通常,我希望没有用户能够编辑自己的角色.普通用户可以编辑自己的文档,否则管理员可以编辑任何人的文档.

In general, I want no users to be able to edit their own role. Regular users can edit their own document otherwise, and admins can edit anyone's.

isEditingRole()插入isEditingRole()可以得到预期的结果,所以我将其缩小为该表达式.

Stubbing isEditingRole() for false gives the expected result, so I've narrowed it down to that expression.

写操作一直返回假,我无法确定原因.任何想法或修复都将有所帮助!

The write keeps coming back false, and I cannot determine why. Any ideas or fixes would be helpful!

编辑1

我尝试过的事情:

function isEditingRole() {
  return request.resource.data.keys().hasAny(['role']);
}

function isEditingRole() {
  return 'role' in request.resource.data;
}

function isEditingRole() {
  return 'role' in request.resource.data.keys();
}

编辑2

请注意,管理员最终将为用户设置角色,因此角色最终可能会存在于文档中.这意味着,根据下面的 Firestore文档,该请求将甚至在原始请求中也没有role键.

Note that eventually, admins will set a role for users, so a role could eventually exist on a document. This means that, according to the Firestore docs below, the request will have a role key, even if wasn't in the original request.

请求中未提供的,资源中存在的字段将添加到request.resource.data.规则可以通过比较request.resource.data.fooresource.data.foo来测试字段是否被修改,知道即使resource中的每个字段也都出现在request.resource中,即使该字段不是在写入请求中提交的.

Fields not provided in the request which exist in the resource are added to request.resource.data. Rules can test whether a field is modified by comparing request.resource.data.foo to resource.data.foo knowing that every field in the resource will also be present in request.resource even if it was not submitted in the write request.

因此,我认为排除了编辑1"中的三个选项.我确实尝试过request.resource.data.role != resource.data.role的建议,但它也不起作用……我很茫然,开始怀疑Firestore中是否确实存在错误.

According to that, I think the three options from "Edit 1" are ruled out. I did try the suggestion of request.resource.data.role != resource.data.role and that's not working either... I'm at a loss and am beginning to wonder if there's actually a bug in Firestore.

推荐答案

所以最后,我似乎以为resource.data.nonExistentField == null会返回false,而实际上却返回了Error(根据和我的测试).因此,我最初的解决方案可能已经遇到了这种情况.这令人困惑,因为相反的方法应该根据文档起作用,但是也许文档所指的是不存在"的值,而不是键,这是一个微妙的区别.

So in the end, it seems I was assuming that resource.data.nonExistentField == null would return false, when it actually returns an Error (according to this and my tests). So my original solution may have been running into that. This is puzzling because the opposite should work according to the docs, but maybe the docs are referring to a value being "non-existent", rather than the key -- a subtle distinction.

我仍然没有100%的清晰度,但这就是我最终成功的原因:

I still don't have 100% clarity, but this is what I ended up with that worked:

function isAddingRole() {
  return !('role' in resource.data) && 'role' in request.resource.data;
}

function isChangingRole() {
  return 'role' in resource.data && 'role' in request.resource.data && resource.data.role != request.resource.data.role;
}

function isEditingRole() {
  return isAddingRole() || isChangingRole();
}

让文档困扰的另一件事是,根据文档,我不需要isChangingRole()中的&& 'role' in request.resource.data部分,因为它应该由Firestore自动插入.尽管事实并非如此,但删除它会导致我的写入因权限问题而失败.

Another thing that still puzzles me is that, according to the docs, I shouldn't need the && 'role' in request.resource.data part in isChangingRole(), because it should be inserted automatically by Firestore. Though this didn't seem to be the case, as removing it causes my write to fail for permissions issues.

可以通过将写入分为createupdatedelete部分而不只是allow write: if !isEditingOwnRole() && (isOwnDocument() || isAdmin());来澄清/改进.

It could likely be clarified/improved by breaking the write out into the create, update, and delete parts, instead of just allow write: if !isEditingOwnRole() && (isOwnDocument() || isAdmin());.

这篇关于Firestore安全规则-如何检查字段是否已被修改?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆