Firebase Firestore动态更新安全规则

Firebase Firestore动态更新安全规则,firebase,google-cloud-firestore,firebase-security,Firebase,Google Cloud Firestore,Firebase Security,假设我们有一个聊天应用程序,在这个应用程序中,我们有很多房间,一些是私人房间,一些是供每个人使用的。每个房间都有一个管理员,可以管理用户(可以邀请和删除)。只有房间里的人才能读写信息。管理员是在此场景中创建房间的人 我想在创建聊天室时创建安全规则,并在membersChange上更新它,这样只有会员才能读写留言板的内容 在这种情况下,它可能是这样的: databse/rooms/ private1 admin: memberX

假设我们有一个聊天应用程序,在这个应用程序中,我们有很多房间,一些是私人房间,一些是供每个人使用的。每个房间都有一个管理员,可以管理用户(可以邀请和删除)。只有房间里的人才能读写信息。管理员是在此场景中创建房间的人

我想在创建聊天室时创建安全规则,并在membersChange上更新它,这样只有会员才能读写留言板的内容

在这种情况下,它可能是这样的:

databse/rooms/
             private1 
                admin: memberX
                members: member1, member2
                //only admin can write into members fields
                messages
                    message1...
                    message2...
                    message3...
                //only members can write and read messages

             private2 
                admin: memberXY
                members: member1, member4
                //only admin can write into members fields
                messages
                    message1...
                    message2...
                    message3...
                //only members can write and read messages
那么,是否可以从云功能创建和更新安全规则,而不是在firebase控制台中手动更新它们?或者是否有任何方法可以自动化此过程?

我注意到我可以。这里的流程应该是什么?我什么时候叫它?如何从数据库中获取成员

编辑:
对于任何想了解更多信息的人,我会重新考虑这个模型。我没有一直更新安全规则,而是看到了几种可行的方法:

选项1

您可以保存哪些用户可以访问Firestore上的特定文件室,然后根据安全规则,您可以访问该文件室的文档,并查看经过身份验证的用户是否在授权用户列表中。这样做的问题是成本,因为这将为每个操作触发额外的数据库读取,这可能会很昂贵

选项2

您可以使用云函数为用户创建自定义声明,如下所示:

admin.auth().setCustomUserClaims(uid, {"rooms": "room1,room2"})
然后,在安全规则上,您可以检查用户是否拥有对特定房间的声明:

match /rooms/{roomId} {
  allow read: if roomId in request.auth.token.rooms.split(',');
}
我相信您也可以直接将声明保存为数组,但我还没有测试它

对于这个选项,您需要考虑令牌的大小,它有一个限制,如果太大,可能会导致性能问题。根据您的场景,您可以创建一组较小的权限,然后将这些权限设置为文件室和用户

选项3

您可以保存可以访问每个文档的用户的uid,然后检查该文档上是否存在经过身份验证的用户的uid。但如果用户太多,这可能会失控


如果对您的场景有意义,我会选择选项2。或者您可以将这些技术中的多个结合起来。我的想法是展示一些可能性,以便您可以选择适合您的产品。

我会重新思考这个模型。我没有一直更新安全规则,而是看到了几种可行的方法:

选项1

您可以保存哪些用户可以访问Firestore上的特定文件室,然后根据安全规则,您可以访问该文件室的文档,并查看经过身份验证的用户是否在授权用户列表中。这样做的问题是成本,因为这将为每个操作触发额外的数据库读取,这可能会很昂贵

选项2

您可以使用云函数为用户创建自定义声明,如下所示:

admin.auth().setCustomUserClaims(uid, {"rooms": "room1,room2"})
然后,在安全规则上,您可以检查用户是否拥有对特定房间的声明:

match /rooms/{roomId} {
  allow read: if roomId in request.auth.token.rooms.split(',');
}
我相信您也可以直接将声明保存为数组,但我还没有测试它

对于这个选项,您需要考虑令牌的大小,它有一个限制,如果太大,可能会导致性能问题。根据您的场景,您可以创建一组较小的权限,然后将这些权限设置为文件室和用户

选项3

您可以保存可以访问每个文档的用户的uid,然后检查该文档上是否存在经过身份验证的用户的uid。但如果用户太多,这可能会失控


如果对您的场景有意义,我会选择选项2。或者您可以将这些技术中的多个结合起来。我的想法是展示一些可能性,以便您可以选择适合您的房间。

每个房间都有不同的规则,并动态更新规则是个坏主意。以下是使用此解决方案时想到的几个问题:

  • 谁将更新规则
  • 同时创建两个房间时会发生什么情况
  • 出问题时会发生什么
  • 当你有一百万间房间时,你将如何维持你的规则
相反,您可以首先将数据结构分为公共房间和私人房间:
数据库/rooms/public/…
数据库/rooms/private/…

为了保护您的私人房间,您可以查看并执行以下操作:
如果成员的UID位于/members
(伪代码,不会这样工作)


你可以看一个例子。

为每个房间制定不同的规则并动态更新规则是个坏主意。以下是使用此解决方案时想到的几个问题:

  • 谁将更新规则
  • 同时创建两个房间时会发生什么情况
  • 出问题时会发生什么
  • 当你有一百万间房间时,你将如何维持你的规则
相反,您可以首先将数据结构分为公共房间和私人房间:
数据库/rooms/public/…
数据库/rooms/private/…

为了保护您的私人房间,您可以查看并执行以下操作:
如果成员的UID位于/members
(伪代码,不会这样工作)


您可以查看一个示例。

这听起来像是一个糟糕的做法,或者可能是XY问题。例如,是否有可能更改您的数据库结构?@AndréKool有可能,但如何在不丢失某些功能的情况下进行更改?为什么这是一种不好的做法呢?我建议你研究一下,如果会员的UID在/members中,会员可以读/写什么,以获得一个可能的解决方案