【问题标题】:Access parent documents field in Firestore rules访问 Firestore 规则中的父文档字段
【发布时间】:2018-07-04 11:49:10
【问题描述】:

我在 Firestore 中实现了一本食谱书,其中每个用户都可以看到所有用户创建的所有食谱,但只有食谱的原始作者可以编辑或删除食谱。还允许任何用户创建新配方。

我的问题是我无法设置子集合在子集合父文档的字段上“侦听”的权限。

每个配方文档包含三件事。一个名为 name 的字段用于存储配方名称,一个名为 creatorUID 的字段用于存储创建者 uid 的 request.auth.uid 以及一个名为 ingredients 的子集合,其中包含带有一些随机字段的文档。

service cloud.firestore {
  match /databases/{database}/documents {

    function isSignedIn() {
      return request.auth != null;
    }

    match /ListOfRecipes/{recipe} {
        allow read, create: if isSignedIn();
        allow update, delete: if resource.data.creatorUID == request.auth.uid;

        match /{list=**} {
            allow read: if isSignedIn();
            // Should return true if recipe.creatorUID has same value as request.auth.uid
            allow write: if recipe.creatorUID == request.auth.uid;
        }
    }
  }
}

问题在于,这些规则仅适用于创建配方文档。由于数据库说,子集合及其文档没有创建

FirebaseError:[code=permission-denied]:权限缺失或不足。 FirebaseError:缺少权限或权限不足。

调用来自 Angular 客户端及其官方库。

【问题讨论】:

  • 你在match /{list=**}里面试过allow write: if request.data.creatorUID == request.auth.uid;吗?
  • 据我所知 request.data 包含要写入的数据,因为我不想写那段数据......或者?......

标签: firebase firebase-security angularfire2 google-cloud-firestore


【解决方案1】:

规则不会级联,因此您需要对规则捕获的文档执行所需的任何检查。

一般来说,{x=**} 规则通常是错误的,=** 的使用仅用于极其具体的用例。

根据您的问题,我假设您的数据模式是这样的:

/ListofRecipes/{recipe_document}/List/{list_document}

在这种情况下,您需要像这样配置规则:

service cloud.firestore {
  match /databases/{database}/documents {

    function isSignedIn() {
      return request.auth != null;
    }

    match /ListOfRecipes/{recipe} {
        allow read, create: if isSignedIn();
        allow update, delete: if resource.data.creatorUID == request.auth.uid;

        function recipeData() {
            return get(/databases/$(database)/documents/ListOfRecipes/$(recipe)).data
        }

        match /List/{list} {
            allow read: if isSignedIn();
            allow write: if recipeData().creatorUID == request.auth.uid;
        }
    }
  }
}

【讨论】:

  • @Payerl 这是一个很好的解决方案,但是,您应该非常注意这个问题。每次运行 recipeData() 函数时,它都会计入您需要付费的读取次数。因此,如果经常写入该子集合,它将很快变得非常昂贵。
  • 有更好的方法吗?
  • 你能确认这仍然有效吗?我感觉最近(实际上是从今天开始)嵌套路径也执行父规则,并且在您的示例中尝试访问 resource.data.creatorUID 时失败。
【解决方案2】:

丹上面的回答效果很好!仅供参考,在我的情况下,我只需要根父文档 ID,您可以使用嵌套语句上方的 match 语句中的变量,如下所示:

service cloud.firestore {
  match /databases/{database}/documents {

    function isSignedIn() {
      return request.auth != null;
    }

    match /ListOfRecipes/{recipeID} {
        allow read, create: if isSignedIn();
        allow update, delete: if resource.data.creatorUID == request.auth.uid;

        match /List/{list} {
            allow read: if isSignedIn();
            allow write: if  recipeID == 'XXXXX';
        }
    }
  }
}

【讨论】:

  • 您不需要按照 Dan 的 recipeData() 函数将其写为 $(recipeID) 吗? recipeID$(recipeID) 都在这里工作,还是只在 recipeID 工作?
【解决方案3】:

根据 Dan 的回答,您应该能够通过将 creatorUID 添加到子集合文档中来减少子集合上 updatedelete 的数据库读取次数。

您必须将 create 限制为仅创建者,并确保设置了 creatorUID。这是我对 Dan 规则的修改:

service cloud.firestore {
  match /databases/{database}/documents {

    function isSignedIn() {
      return request.auth != null;
    }

    match /ListOfRecipes/{recipe} {
        allow read, create: if isSignedIn();
        allow update, delete: if resource.data.creatorUID == request.auth.uid;

        function recipeData() {
            return get(/databases/$(database)/documents/ListOfRecipes/$(recipe)).data
        }

        match /List/{list} {
            allow read: if isSignedIn();
            allow update, delete: if resource.data.creatorUID == request.auth.uid;
            allow create: if recipeData().creatorUID == request.auth.uid
                          && request.resource.data.creatorUID == request.auth.uid;
        }
    }
  }
}

【讨论】:

    猜你喜欢
    • 2023-04-08
    • 2018-09-29
    • 2022-01-19
    • 2023-02-13
    • 1970-01-01
    • 2020-12-22
    • 1970-01-01
    • 2018-07-21
    • 1970-01-01
    相关资源
    最近更新 更多