Firestore安全规则编写求助:仅允许聊天成员读写指定文档及其子集合
Firestore安全规则实现方案
针对你的聊天应用场景,我们可以通过结合文档ID格式验证+文档内users数组检查的方式,精准控制只有聊天成员能读写对应文档及其子集合。下面是完整的规则实现和详细解释:
service cloud.firestore { match /databases/{database}/documents { // 辅助函数:从聊天ID拆分用户ID,验证当前用户是否为聊天成员 function isChatMember(chatId) { let splitIds = split(chatId, '.'); // 确保拆分出两个有效ID,且当前用户是其中之一 return request.auth != null && splitIds.size() == 2 && (request.auth.uid == splitIds[0] || request.auth.uid == splitIds[1]); } // 辅助函数:验证当前用户在文档的users数组中(双重校验) function isMemberInUsersList(doc) { return request.auth != null && request.auth.uid in doc.data.users; } // 主聊天文档的权限控制 match /chats/{chatId} { // 读写权限:同时满足ID拆分验证和users数组校验,双重保障 allow read, write: if isChatMember(chatId) && isMemberInUsersList(resource); // 可选:细化创建规则,确保文档创建时格式合规 allow create: if isChatMember(chatId) && request.resource.data.users == split(chatId, '.') && request.resource.data.createdAt is timestamp && request.resource.data.lastChat is string && request.resource.data.lastMessageSent is timestamp; // 可选:细化更新规则,限制只能修改允许的字段 allow update: if isChatMember(chatId) && isMemberInUsersList(resource) && request.resource.data.diff(resource.data).affectedKeys().hasOnly( ['lastChat', 'lastMessageSent'] ); // 子集合messages的权限控制 match /messages/{messageId} { // 直接复用聊天ID的成员验证(无需额外读取父文档,性能更优) allow read, write: if isChatMember(chatId); // 如果你更依赖父文档的users数组,也可以用下面的规则(需要读取父文档,性能稍差) // allow read, write: isMemberInUsersList(get(/databases/$(database)/documents/chats/$(chatId))); } } } }
关键规则解释
isChatMember辅助函数:
利用你定义的chatId格式(userA.userB),通过split函数拆分出两个用户ID,直接验证当前登录用户是否为其中之一。这种方式不需要读取文档数据,性能更高,适合快速权限校验。isMemberInUsersList辅助函数:
作为双重校验,检查文档的users数组是否包含当前用户ID,防止出现chatId格式正确但users数组不匹配的异常情况,提升安全性。创建/更新的细化规则:
- 创建时强制
users数组和chatId拆分出的ID完全一致,同时校验所有必填字段的类型,避免脏数据。 - 更新时限制只能修改
lastChat和lastMessageSent字段,防止成员篡改createdAt、users等核心数据。
- 创建时强制
子集合
messages的权限:
直接复用chatId的验证逻辑即可,因为能访问父聊天文档的用户必然是成员,无需重复校验。如果需要更严格依赖父文档的users数组,可以用get函数读取父文档进行校验,但会增加一次文档读取操作。
注意事项
- 客户端创建聊天文档时,建议按字母排序生成
chatId(比如user1234.user4321而不是user4321.user1234),避免生成重复的聊天文档。 - 确保用户登录状态(
request.auth != null)是所有权限校验的前提,未登录用户无法访问任何聊天数据。
内容的提问来源于stack exchange,提问作者Kevin Miller
相关产品推荐
相关产品推荐

