文档字段的 Firestore 规则

Posted

技术标签:

【中文标题】文档字段的 Firestore 规则【英文标题】:Firestore rules for document field 【发布时间】:2018-09-29 20:56:17 【问题描述】:

我在 Firestore 中为文档设置安全规则而苦苦挣扎。使用 RTDB 可以为特定对象属性设置规则,我正在尝试对 Firestore 做同样的事情。

RTDB 代码:

"users": 
    ".read": true,
    ".indexOn": ["profile/name"],
    "$uid": 
        ".read": "auth != null",
        ".write":
            "$uid === auth.uid && !data.exists()",
        "profile": 
            "birthday": 
                ".write": "$uid === auth.uid"
            ,
            "name": 
                ".write": "$uid === auth.uid"
            ,
            "banned": 
                ".write": "root.child('admins').child(auth.uid).exists()"
            
        
    

在 Firestore 中的相同代码下方:

service cloud.firestore 
    match /databases/database/documents 
        match /users/ 
            allow read
            match /$user 
                allow read: if request.auth.uid != null
                allow write: if request.auth.uid == request.resource.id &&  exists(/databases/$(database)/documents/users/$(request.resource.id)) === false

                match /birthday 
                    allow write: if request.auth.uid == request.resource.id
                
                match /name 
                    allow write: if request.auth.uid == request.resource.id
                
                match /banned  
                    allow write: get(/databases/$(database)/documents/users/$(request.auth.uid)).data.userType > 3
                

            
        
    

当我为子集合编写安全规则时,它工作正常。但是对于文档字段,它不起作用。这是不可能的还是匹配参考中有一个特殊的path 段? The documentation 对此没有任何说明。

【问题讨论】:

【参考方案1】:

您可以通过检查request.resource.data 属性来做到这一点。如documentation的这一部分所示。您只需要匹配文档级别。您使用if 条件检查字段规则。

但是,您无法控制对单个字段的读取权限。用户可以阅读或不阅读整个文档。如果您需要存储私有数据,请考虑将其添加到用户文档的子集合中。

这是一个例子

service cloud.firestore 
  match /databases/database/documents 
    // Make sure all cities have a positive population and
    // the name is not changed
    match /cities/city 
      allow update: if request.resource.data.population > 0
                    && request.resource.data.name == resource.data.name;
    
  

【讨论】:

这可能适用于写入,但不适用于读取。它还创建了更多的意大利面条代码。 对于读取,您只需省略 request. 我发给您的文档链接中显示了一个示例 我正在尝试了解您对 banned 字段的操作。您能否用所需的结果更新您的问题并发表评论,以便我看一下? 使用 Cloud Firestore,您无法限制单个字段的读取。您只能允许/阻止阅读文档。但是,可以控制单个字段的写入。如果您希望存储私有数据,您应该向用户文档添加一个集合,该集合可以包含此私有数据。我通常有 3 个集合,publicprivate(用户可以访问)和internal。你也可以添加一个admin 集合。 也许这会有所帮助:您可以使用writeFields property 访问传入写入的目标字段。所以你可以这样做:allow write: if isAdministrator() || !('banned' in request.writeFields);【参考方案2】:

Looks like this is now supported:

service cloud.firestore 
  match /databases/database/documents 
    // Allow the user to read data if the document has the 'visibility'
    // field set to 'public'
    match /cities/city 
      allow read: if resource.data.visibility == 'public';
    
  

resource 变量引用请求的文档,resource.data 是存储在文档中的所有字段和值的映射。


举一个具体的例子,在我的例子中,只有当请求用户在 groups 的 members 字段(这是一个数组)中时,我才需要提供对组的读取访问权限 集合。所以我这样做了:

rules_version = '2';
service cloud.firestore 
  match /databases/database/documents 
    function isMember(userId) 
      return (userId in resource.data.members);
    
    match /groups/group 
      allow read: if request.auth != null && isMember(request.auth.uid);
    
    //...
  

【讨论】:

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

即使firestore安全规则中的文档字段不可用,也如何允许访问?

有没有办法使用Firestore安全规则使用FieldValue.increment()更新文档字段?

Firestore 安全规则 - 如何检查某个字段是不是被修改?

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

Firebase Firestore 安全规则 |如果字段值与 auth uid 相同,则允许读取

如何在 Firestore 规则中同时发生两个查询