我的第一个问题是我们如何指定此数据库定义的安全规则?有一些最佳实践方法吗?
我们的第一个想法就是这样做:
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));
}
感谢您提供有关如何以最具扩展性,尤其是最安全的方式构建它的任何建议。
答案 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)
我想过的一种与我们正在从事的工作类似的方法,即只有某些用户有权访问的私人聊天室,是使用服务器上的密钥加密所有消息,并仅授予该用户的读取访问权限某些用户的关键。这样,仅当第一次获得密钥时,额外的只读操作必须发生一次,然后没有附加安全规则的正常读取就可以了,因为攻击者无法进行任何操作,因为它们已加密并且他们无权访问密钥。