【发布时间】:2019-12-30 11:16:40
【问题描述】:
短版
我正在使用 firestore 构建一个应用程序,用户可以在其中创建课程、向这些课程添加资源,然后让其他用户注册他们的课程,这将使他们能够访问其所有资源。 我正在努力设置安全规则,以便只有课程组织者或课程成员才能访问资源。 我的主要问题是允许用户列出他们注册的课程中的所有资源,因为列表请求不允许在安全规则中进行查询,我需要检查该用户是否是该课程的成员。 让数百(或可能数千)课程成员轻松列出所有课程资源,同时确保非成员无法访问它的最佳方法是什么?
在docs 的限制部分中,它特别提到将角色移动到大型或复杂组的单独集合中,但这样做将需要安全规则执行查询以检查访问权限,这对于列表请求是不可能的。
完整版
我正在创建一个客户端直接访问 firestore 的原型 Web 应用程序。消除对后端处理简单数据访问的需求令人耳目一新,但我现在真的很难为我的用例制定正确的数据结构和方法,尤其是在实施适当的安全规则方面。
我曾广泛使用关系数据库,但对 nosql 数据库和 firestore 还是很陌生,特别是没有帮助。
概念
我的应用程序中的主要集合是用户、课程和资源。 用户可以创建他们创建学习资源的课程,然后其他用户可以注册这些课程,因此可以访问其中的所有资源。 由于某些课程只会被邀请,因此用户无法访问他们不是其成员的课程的资源。
主要要求是:
- 课程组织者需要对其课程和资源的完全读写权限。
- 课程成员需要对其课程和资源的完全阅读权限。
- 组织者和成员都需要能够轻松列出他们的所有课程,并为每门课程列出他们的所有资源。
- 组织者和成员不应检索不属于他们的课程或资源的相关信息。
我的方法
首先我的方法是大量利用子集合。 从组织者的角度来看,用户的课程有资源,所以我就是这样建模的。
用户 -> 课程 -> 资源
组织者的安全规则在这里也非常简单,因为用户 ID 是文档路径的一部分,它可以通过可用的用户 uid 轻松检查(感谢 firebase auth)。
即
match /users/{userId}/courses/{courseId}/resources/{resourceId} {
allow read, write, update, delete: if (request.auth.uid == userId)
}
但事实证明,授予成员只读访问权限有点困难。我需要合适的地方来存储该映射。
我最终尝试使用用户子集来存储它,因此可以通过以下方式查找课程成员资格:
/users/{userId}/course_memberships/{courseId}
理论上我可以编写一个安全规则来授予对课程和资源的读取权限,如下所示:
match /users/{userId}/courses/{courseId}/resources/{resourceId} {
allow read: if exists(/databases/$(database)/documents/users/$(request.auth.uid)/course_memberships/${courseId})
}
但这仅在检索单个文档时有效,列表请求不会评估安全规则中的查询,因此此设置不允许课程成员查看给定课程中所有资源的列表。
我无法弄清楚这里的正确方法是什么,我看到的唯一选项是:
-
为每个成员创建一个单独的集合层次结构,其中包含他们的所有课程和所有资源,包括用于列出其资源的关键信息,并使用云功能同步这些信息。我知道 nosql 是关于存储非规范化的数据,但这感觉像是很多额外的数据,特别是当它只是安全规则所必需的时候。
-
将每个成员的 uid 添加到每个资源的数组中(可以 每个数以千计),这也感觉像很多额外的数据,它会 将这些 id 暴露给所有其他似乎错误的成员。
这里有没有更好的方法,还是 firestore 不太适合这种类型的问题?
希望这个问题尚未得到解答,我进行了搜索,但找不到涵盖完全相同场景的内容。
【问题讨论】:
-
你是怎么解决的?我有同样的问题:(
标签: firebase google-cloud-firestore firebase-security