Firestore子集合与集合组查询的安全规则配置问题
问题:Firestore子集合查询权限配置问题
数据结构
Users - w34rj3d9d2383 - name - email - items (sub-collection) - dj23jd23wkjdkl - name - notes - createdBy - 4ru328rjwiodj2309 - name - notes - createdBy
问题描述
当前在现有安全规则下,能指定userId和itemId订阅已认证用户的items子集合单个条目,也能不添加谓词获取指定用户所有items,但添加谓词查询时无结果返回。
Swift查询代码
let path = "users/w34rj3d9d2383/items" let predicate = NSPredicate(format: "SELF.name CONTAINS %@", name) let collectionReference = Firestore.firestore().collection(path).filter(using: predicate) collectionReference.addSnapshotListener(includeMetadataChanges: false) { querySnapshot, error in //... }
现有安全规则
rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { match /users/{userId} { allow read, update, delete: if request.auth != null && request.auth.uid == userId; allow create: if request.auth != null; } match /users/{userId}/{document=**}{ allow read, update, delete: if request.auth != null && request.auth.uid == userId; allow create: if request.auth != null; } } }
更新记录
更新1
尝试以下操作仍有权限问题:
- 将引用改为集合组:
let collectionReference = Firestore.firestore().collectionGroup("items").filter(using: predicate)
- 规则中添加:
match /{path=**}/items/{itemId} { allow list: if request.auth.uid == resource.data.createdBy; allow get: if request.auth.uid == resource.data.createdBy; }
更新2
使用以下规则成功实现查询,但权限过宽:
match /{path=**}/items/{itemId} { allow read, write: if request.auth != null; }
此规则下,集合组查询能获取所有items,但希望仅返回resource.data.createdBy与request.auth.uid匹配的条目,添加该验证条件时系统提示resource为null,求解决方法。
解决方案
问题根源
用集合组查询时,Firestore安全规则执行list操作权限检查时,会先验证整个查询而非逐个文档,此时resource对象仅在单个文档的get操作中有效,list(多文档查询)时resource为null,这就是报错原因。
正确配置方式
分两种场景处理:
1. 仅查询当前用户自己的items子集合
无需用集合组,直接保留原路径,原规则已经满足权限要求。如果查询仍无结果,检查:
- 当前认证用户的
uid是否确实等于w34rj3d9d2383 - 谓词中的
name参数是否正确,是否存在匹配的文档
2. 集合组跨用户查询(仅返回自己创建的条目)
需要同时验证查询条件和用户身份,确保查询必须包含createdBy == 当前用户uid的过滤逻辑:
修改安全规则:
rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { // 保留原用户文档规则 match /users/{userId} { allow read, update, delete: if request.auth != null && request.auth.uid == userId; allow create: if request.auth != null; } // 保留单个用户子集合规则 match /users/{userId}/{document=**}{ allow read, update, delete: if request.auth != null && request.auth.uid == userId; allow create: if request.auth != null; } // 集合组查询的items规则 match /{path=**}/items/{itemId} { // 单个文档查询:验证createdBy匹配当前用户 allow get: if request.auth != null && request.auth.uid == resource.data.createdBy; // 多文档查询:强制查询必须包含createdBy等于当前用户的条件 allow list: if request.auth != null && request.query.where('createdBy', '==', request.auth.uid); } } }
修改Swift查询代码,必须添加createdBy过滤条件:
guard let currentUid = Auth.auth().currentUser?.uid else { return } let nameFilter = NSPredicate(format: "SELF.name CONTAINS %@", name) let userFilter = NSPredicate(format: "createdBy == %@", currentUid) let combinedPredicate = NSCompoundPredicate(andPredicateWithSubpredicates: [nameFilter, userFilter]) let collectionReference = Firestore.firestore().collectionGroup("items").filter(using: combinedPredicate) collectionReference.addSnapshotListener(includeMetadataChanges: false) { querySnapshot, error in //... }
关键说明
Firestore安全规则不会自动过滤数据,只会验证查询是否符合权限要求。如果规则要求查询必须包含createdBy == 当前用户,代码必须显式添加该条件,否则规则会直接拒绝整个查询。
内容的提问来源于stack exchange,提问作者VAlexander
相关产品推荐
相关产品推荐

