【问题标题】:Firestore rules for document field文档字段的 Firestore 规则
【发布时间】: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 对此没有任何说明。

【问题讨论】:

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


    【解决方案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 个集合,public、private(用户可以访问)和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);
        }
        //...
      }
    }
    

    【讨论】:

      猜你喜欢
      • 2018-07-04
      • 2023-02-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-08
      • 2018-06-03
      • 2020-06-19
      相关资源
      最近更新 更多