firebase 我如何编写firestore规则来适应多用户树数据结构?--考虑可共享的todo项与子项

kb5ga3dv  于 2023-11-21  发布在  其他
关注(0)|答案(2)|浏览(109)

firestore数据代表一个工件集合,每个工件都有一个usersIds字段(稍后会详细介绍)和一个parentId字段,parentId字段是null(如果这是一个根工件),或者包含同一集合中另一个工件的id
根工件可以在多个用户之间共享。因此,每个parentId等于null的文档在其usersIds字段中都有一个id值的数组。该工件以及集合中从属于它的所有其他工件都可以由该数组上的用户查看和编辑。
对象只能在根级别配置。子对象不能覆盖在其根中设置的内容。
举例来说:

{ id: 'a', parentId: null, usersIds: ['joe', 'jane'] }
{ id: 'a1', parentId: 'a' } 
{ id: 'a11', parentId: 'a1' } 
{ id: 'b', parentId: null, usersIds: ['mary'] } 
{ id: 'b1', parentId: 'b' }

字符串
根据上面的例子,joe可以看到a、a1和a11,但不能看到b或b1。
我如何编写firestore规则来强制执行前面讨论的内容?我可以使用递归函数吗?

oxalkeyp

oxalkeyp1#

这在安全规则中很难做到,因为没有办法在必要的文档上循环。记住安全规则不会过滤实际数据,而只是确保查询只请求它有权读取的数据。
就像我不认为你可以在当前数据结构上捕获你的安全规则需求一样,我甚至想不出一个只请求正确文档的查询。Firestore查询只能过滤它们返回的文档中的数据,在这种情况下,你实际上是在尝试过滤“父”工件中的数据-这可能不是返回。
对于这种类型的授权模型,您通常需要将有权访问工件的每个人的用户ID反规范化到该特定工件中。因此,您最终会得到这样的结果:

{ id: 'a', parentId: null, usersIds: ['joe', 'jane'] }
{ id: 'a1', parentId: 'a', usersIds: ['joe', 'jane'] } 
{ id: 'a11', parentId: 'a1', usersIds: ['joe', 'jane'] } 
{ id: 'b', parentId: null, usersIds: ['mary'] } 
{ id: 'b1', parentId: 'b', usersIds: ['mary'] }

字符串
有了这个数据结构,您的查询突然变得非常简单,并且您的安全规则可以检查实际正在考虑的文档的usersIds字段-而不需要执行一个或多个级别的父查找。

rkkpypqq

rkkpypqq2#

你需要使用existsget和数组函数。你可以在这里看到使用列表的函数:https://firebase.google.com/docs/reference/rules/rules.List
你也可以编写原始函数,例如(这只是你应该做的一个例子,它不起作用):

rules_version = '2';
service cloud.firestore {
    match /databases/{database}/documents {

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

        function getArtifactPath(id) {
            return (/databases/$(database)/documents/artifacts/$(id));
        }

        function getArtifactData(id) {
            return get(getUserPath(id)).data;
        }

        match /artifacts/{id}{
            allow read, write: if (
                isSignedIn() && (
                    request.auth.uid in resource.data.usersIds ||
                    request.auth.uid in getArtifactData(resource.data.parentId).data.usersIds ||
                    request.auth.uid in getArtifactData(getArtifactData(resource.data.parentId).data.parentId).data.usersIds
                )
            );
        }
    }
}

字符串
我还建议您在每个文档中都有一个完整的usersIds,因为规则不支持循环,您必须手动绘制N个级别(见下例)。此外,您将为阅读每个将在规则级别提取的文档付费。如果您需要树结构,您可以将自己的规则放置在其中一个文档中,并在规则中使用。例如,使用路径/artifacts/a/b/${docId}并在文档中放置像{ "/artifacts/a/b": ["userId1", "userId2"]}这样的规则,然后使用request.path、request.auth.uid、string和array函数。

相关问题