Firestore - 公司内部用户的安全规则

时间:2018-03-08 22:43:56

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

我们目前的Firestore结构如下: enter image description here

  • 目前我们没有使用任何子收藏
  • 用户拥有他们所属的公司列表
  • 每个项目仅与1家公司
  • 相关联
  • 项目属于公司,当在companyId字段中写入公司UID

我的第一个问题是我们如何指定此数据库定义的安全规则?有一些最佳实践方法吗?

我们的第一个想法就是这样做:

match /databases/{database}/documents/projects/{projectUid}/{document=**} {
allow read: if 
(/databases/$(database)/documents/projects/$(projectUid)/companyId) === 
(/databases/$(database)/documents/users/$(request.auth.uid)/companyId)
}

但根据文档,这意味着我们每次读取基本上都会有3次读取(2次安全查询和1次真实读取)。这似乎是在浪费查询。

有比这更好的方法吗? 我们正在考虑改为子集:

  • 最后我们会在根集合'公司'和'用户' (存储所有用户详细信息)
  • 项目将是公司的子集合
  • 页面将是项目的子收集
  • ...等
  • 并且公司会包含用户列表(不像现在这样反过来) - 但只列出,而不是用户详细信息

这样我们就可以使用与doc相似的方法,其中每个匹配包含{companyId},在allow语句中我们可以使用类似

的方法
match /databases/{database}/documents/companies/{companyId}/projects/{projectId} {
    allow read: if
    exists(/databases/$(database)/documents/companies/$(companyId)/users/$(request.auth.uid));
}

感谢您提供有关如何以最具扩展性,尤其是最安全的方式构建它的任何建议。

3 个答案:

答案 0 :(得分:4)

您考虑过adding a user's company ID as a custom claim to their profile了吗?这样,您的安全规则就不需要额外的读取。

由于设置这些声明需要管理员SDK,因此需要您可以在某处运行受信任的代码。但是,如果您还没有自己的可信任环境,那么可以使用Cloud Functions基于其他一些操作,例如写入当前的Firestore结构。

答案 1 :(得分:0)

为弗兰克添加答案。

从其他API SDK(例如Microsoft graph)借用,通常是通过使用表示用户范围/权利的身份验证令牌初始化Client对象来发起资源请求。例如:

const client = new SDKClient(my_auth_token);

客户端构造函数将对声明具有令牌验证步骤。然后,您可以进行REST调用,例如

const response = await client.someEndpoint({ method: 'POST', body: my_object });

我建议您使用常规的Firebase Node.js客户端,而不是使用管理SDK来读写Firestore。要使用安全规则限制访问,请将Firebase JWT令牌与您从请求标头获得的令牌一起传递到此自定义SDKClient类中。在构造函数中,初始化一个新的firebase'app'。因为常规的Firebase客户端是
根据安全规则,这将满足您的需求。 this answer中已经提供了一些示例代码。

我应该补充一点,根据此firebase doc,有一个'警告'可以使用admin-sdk服务器端,但是我不确定为什么。

答案 2 :(得分:0)

我想过的一种与我们正在从事的工作类似的方法,即只有某些用户有权访问的私人聊天室,是使用服务器上的密钥加密所有消息,并仅授予该用户的读取访问权限某些用户的关键。这样,仅当第一次获得密钥时,额外的只读操作必须发生一次,然后没有附加安全规则的正常读取就可以了,因为攻击者无法进行任何操作,因为它们已加密并且他们无权访问密钥。