访问 Firestore 规则中的父文档字段

Posted

技术标签:

【中文标题】访问 Firestore 规则中的父文档字段【英文标题】:Access parent documents field in Firestore rules 【发布时间】: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 包含要写入的数据,因为我不想写那段数据......或者?...... 【参考方案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;
        
    
  

【讨论】:

以上是关于访问 Firestore 规则中的父文档字段的主要内容,如果未能解决你的问题,请参考以下文章

如何从Swift中的Cloud FireStore Firebase访问特定字段

使用访问规则中的字段写入 Firestore 时缺少权限或权限不足

文档字段的 Firestore 规则

使用 Swift (Firestore) 访问特定文档字段

如何检查传入号码数据是否大于或小于Firestore安全规则中的特定限制?

Firestore - 访问安全规则中的事务/嵌套数据