Firestore安全规则获取参考字段/ ID

时间:2019-03-14 10:01:50

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

我有两个集合-租约和用户。

租户文档的字段名为“ landlordID”,类型为REFERENCE(不是String)。

现在,在我的Firestore安全规则中,仅当租约的landlordID字段与发出请求的用户的uid(即request.auth.uid)匹配时,我才希望允许更新租约。

将其读取为“如果使用户身份经过认证的租户文档得以更新,则request.auth.uid!= null,并且landlordID字段的ID应与request.auth.uid的ID相等。

因此代码应该是这样的:

    service cloud.firestore {

      match /databases/{database}/documents {

        match /tenancies/{tenancyID}{

            allow update: if request.auth.uid != null && 
                        request.auth.uid == get(resource.data.landlordID).id
    }

}

我也尝试过get(/databases/$(database)/documents/users/$(resource.data.landlordID)).data.id

支持我的数据库的屏幕截图

enter image description here

这应该非常简单,但是get()根本不起作用。 Firebase Docs, scroll to "Access other documents"对我的情况完全没有帮助,我不确定如何使它正常工作。

如果引用不能像文档的任何其他字段那样使用,将是一种耻辱。

6 个答案:

答案 0 :(得分:3)

我在这里看到几个问题。第一个问题是get()函数需要一个完整指定的文件路径,例如:

get(/databases/$(database)/documents/users/$(resource.data.landlordID)).data.id

第二个问题是您正在尝试在规则中使用引用类型,不幸的是,我认为这不可能。

Firestore中的引用类型不是非常有用(还),我认为您应该将地主ID存储为字符串,然后可以简单地执行以下操作:

service cloud.firestore {

      match /databases/{database}/documents {

        match /tenancies/{tenancyID}{

            allow update: if request.auth.uid != resource.data.landlordID;

    }

}

答案 1 :(得分:2)

可能为时已晚,但是我能够拼凑(尽管缺少文档)文档引用只是一条路径,并且可以使用以下方式创建完整的路径

/databases/$(database)/documents/users/$(request.auth.uid)

然后我在引用的存储区中有一个数组/列表,称为reads,可以用来抓取:

get(/databases/$(database)/documents/users/$(userId)/userinfo/granted_users).data.reads

让我能够创建布尔值和规则:

/databases/$(database)/documents/users/$(request.auth.uid) in get(/databases/$(database)/documents/users/$(userId)/userinfo/granted_users).data.reads

显然,您的数据结构会有所不同,但是了解ref是路径是这里的重要部分。

答案 2 :(得分:1)

我有一个同样的问题,我需要一个答案。参见this Google-thread以及Google某人的回答。引用它:

  

您可以使用“ index”运算符从路径中获取ID:

     

some_document_ref应该看起来像/databases/(default)/documents/foo/bar

     

有5个细分:["databases", "(default)", ...]

     

some_document_ref[4]应该是“栏”     允许创建:if request.resource.data.some_document_ref [4] ==“ bar”;

     

您还可以在其上使用常规的getexists函数。

     

您可能会遇到的一些困难方面:

     
      
  • 目前无法检索路径中的段数(我们即将添加),因此您需要提前了解有关参考的一些信息

    < / li>   
  • 对于在Firebase控制台中使用模拟器编写参考的支持不大。我使用Firestore模拟器测试了此行为(gist1,gist2)

  •   

答案 3 :(得分:1)

我必须做一些尝试才能使它正常工作。这对我有用的功能

function isUserRef(database, userId) {
  return 'user' in resource.data
    && resource.data.user == /databases/$(database)/documents/users/$(userId);
}

我这样称呼它:

match /answers/{answer} {
   allow read:
        if isUserRef(database, request.auth.uid);
}

答案 4 :(得分:0)

这是我创建的对我有用的功能。我猜您有一个用户集合,这些用户的id与他们的auth.uid

相同
    function isUserRef(field) {
      return field in resource.data
        && resource.data[field] == /databases/$(database)/documents/users/$(request.auth.uid)
    }

根据用例进行调整,可以这样调用该函数:isUserRef('landlordID'),尽管其末尾的ID有点误导,因为该字段实际上是参考。

答案 5 :(得分:0)

正如其他一些答案所提到的,引用有一个 path 属性,它只是一个看起来像 users/randomuserid123 的字符串。您可以将其拆分为一个数组,并将其与发出更新请求的用户进行匹配。

...

match /tenancies/{tenancyID}{

 allow update: if request.auth.uid != null && 
   resource.data.landlordID.path.split('/') == ['users', request.auth.uid]
 }

...