Firebase Firestore安全规则修复求助:聊天通知跨用户读取权限问题
问题描述
我开发了一款简易应用,用户A可向用户B发送聊天、点赞、评论类通知,用户B可接收并读取这些通知。Firestore数据库集合结构如下:
/Notifications/{userId}/NotificationItems/{notificationId}
其中Notifications和NotificationItems为集合,userId是接收通知的用户ID,notificationId是存储通知信息的文档。
最初配置的Firestore规则如下:
match /Notifications/{userId}{ match /NotificationItems/{notificationId} { allow create: if isUserAuthenticated(); allow read: if isUserAuthenticated() && userOwnsResource(userId); allow update: if isUserAuthenticated() && userOwnsResource(userId); } }
配套函数:
function isUserAuthenticated() { return request.auth.uid != null; } function userOwnsResource(userId) { return request.auth.uid == userId; }
这些规则支持通知的获取、发送、标记已读等操作,但发送chat类型通知时,需要先检查是否曾向该用户发送过同聊天的通知(间隔过短则不发送),对应的Firestore调用因权限不足失败:
await firebase .firestore() .collection("Notifications") .doc(userId) .collection("NotificationItems") .where("chatId", "==", chatId) .orderBy("date", "desc") .get()
尝试修改规则添加itIsChatNotification函数,但未生效:
function itIsChatNotification(){ let chatId = get(/databases/$(database)/documents/Notifications/$(userId)/NotificationItems/$(notificationId)).data.chatId; return request.auth.uid in get(/databases/$(database)/documents/Chats/$(chatId)).data.users; }
修改后的读取规则:
allow read: if isUserAuthenticated() && (userOwnsResource(userId) || itIsChatNotification());
解决方案
问题出在原itIsChatNotification函数的实现逻辑:查询操作是批量读取NotificationItems集合,此时notificationId是通配符,无法通过get()获取具体文档的chatId。需要针对查询操作和单个文档读取分别处理,同时确保客户端查询的约束与规则匹配。
正确的Firestore规则
rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { // 验证用户已登录 function isAuthenticated() { return request.auth != null && request.auth.uid != null; } // 用户是通知的接收者 function isNotificationRecipient(userId) { return request.auth.uid == userId; } // 验证当前用户是指定聊天的成员 function isChatMember(chatId) { return exists(/databases/$(database)/documents/Chats/$(chatId)) && request.auth.uid in get(/databases/$(database)/documents/Chats/$(chatId)).data.users; } match /Notifications/{userId}/NotificationItems/{notificationId} { // 创建通知:登录用户可操作,chat类型需验证发送方是聊天成员 allow create: if isAuthenticated() && (request.resource.data.type != "chat" || isChatMember(request.resource.data.chatId)); // 读取通知:两种合法场景 // 1. 用户是通知接收者;2. 读取chat类型通知时,用户是对应聊天成员 allow read: if isAuthenticated() && (isNotificationRecipient(userId) || (resource.data.type == "chat" && isChatMember(resource.data.chatId))); // 更新通知:仅接收者可操作(标记已读等) allow update: if isAuthenticated() && isNotificationRecipient(userId); } } }
客户端查询要求
调用查询时必须添加type的过滤条件,否则规则会拒绝请求:
await firebase .firestore() .collection("Notifications") .doc(userId) .collection("NotificationItems") .where("type", "==", "chat") // 必须添加该条件匹配规则约束 .where("chatId", "==", chatId) .orderBy("date", "desc") .get()
规则说明
- 创建通知:新增chat类型通知的成员验证,避免非聊天成员恶意发送通知。
- 读取通知:
- 单个文档读取:若为chat类型,验证用户是对应聊天成员即可读取;
- 批量查询:通过
resource.data直接获取文档字段做验证,适配查询时的通配符场景。
- 更新通知:仅保留接收者可操作的规则,符合业务逻辑。
内容的提问来源于stack exchange,提问作者newbie coder
相关产品推荐
相关产品推荐

