Firebase Firestore规则编写:仅允许参与者用户访问群组数据
Firebase Firestore规则编写:按参与者权限过滤群组数据
数据结构
stage/data/groups(集合)/ group_name group_id participants(集合)/userid
需求
- 用户调用
groups集合时,仅返回其用户ID存在于对应群组participants集合中的所有群组 - 用户不在
participants集合中的群组,无法访问
尝试过的规则
初始无效规则
rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { function isAuthorised(document){ return exists(/document/participants/$(request.auth.uid)) } match /{document=**} { allow read, write: if isAuthorised(document); } } }
该规则未生效,本人熟悉ASP.NET API中遍历列表返回有效数据的方式,但作为Firebase新手,正在学习复杂的数据保护规则。
更新后的规则(硬编码群组ID时生效)
rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { function isAuthenticated(){ return request.auth.uid != null; } match /{document=**}/groups/{groupid} { allow read, write: if isAuthenticated() && exists(/databases/$(database)/documents/stage/data/groups/$(groupid)/participants/$(request.auth.uid)); } match /{document=**}/users/{userid} { allow read, write: if true; } } }
使用硬编码群组ID时规则生效,但使用$(groupid)变量时无效。
Flutter访问代码
final groupList = await ref.collection(Constants.Environment) .doc("data") .collection("groups").get(); var docs = groupList.docs.toList();
解决方案
正确的Firestore规则
rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { // 验证用户已登录 function isAuthenticated() { return request.auth != null && request.auth.uid != null; } // 验证用户是指定群组的参与者 function isGroupParticipant(groupId) { return exists(/databases/$(database)/documents/stage/data/groups/$(groupId)/participants/$(request.auth.uid)); } // 精确匹配groups集合路径 match /stage/data/groups/{groupId} { // 读取权限:用户已登录且是该群组参与者 allow read: if isAuthenticated() && isGroupParticipant(groupId); // 写入权限可根据实际需求调整,此处暂时与读取权限一致 allow write: if isAuthenticated() && isGroupParticipant(groupId); } // participants子集合权限(可按需调整) match /stage/data/groups/{groupId}/participants/{userId} { allow read, write: if isAuthenticated(); } // 用户集合权限保持不变 match /stage/data/users/{userId} { allow read, write: if true; } } }
关键说明与Flutter查询修改
Firestore安全规则不会自动过滤查询结果,而是验证查询是否符合权限要求。如果直接查询整个groups集合而不加过滤条件,规则会拒绝请求,因为无法确认所有返回的文档用户都有权访问。
需要修改Flutter代码,先获取用户参与的所有群组ID,再查询这些群组:
final currentUserId = FirebaseAuth.instance.currentUser?.uid; if (currentUserId == null) { // 处理未登录场景 return []; } // 先获取用户参与的所有群组ID final participatingGroupIds = await getParticipatingGroupIds(currentUserId); // 仅查询用户有权访问的群组 final groupList = await ref.collection(Constants.Environment) .doc("data") .collection("groups") .where(FieldPath.documentId, whereIn: participatingGroupIds) .get(); var docs = groupList.docs.toList(); // 辅助函数:获取当前用户参与的群组ID列表 Future<List<String>> getParticipatingGroupIds(String userId) async { final participantsSnapshot = await ref.collection(Constants.Environment) .doc("data") .collectionGroup("participants") .where(FieldPath.documentId, isEqualTo: userId) .get(); // 从参与者文档路径中提取群组ID return participantsSnapshot.docs.map((doc) => doc.reference.parent.parent!.id).toList(); }
内容的提问来源于stack exchange,提问作者Prabakaran
相关产品推荐
相关产品推荐

