Firestore规则模拟器测试正常 真机查询时读权限被拒如何解决
问题原因
- 核心原因:Firestore安全规则不是过滤器,不会自动过滤不符合规则的文档。查询执行前Firestore会校验你的查询是否可能返回不符合规则的文档,如果存在这种可能,直接返回权限拒绝,不会逐文档过滤。你当前的查询没有添加隐藏过滤条件,可能返回用户已隐藏的帖子,因此被规则拦截。单文档测试正常是因为单文档获取只会校验单个文档的权限,不会触发该校验逻辑。
- 规则语法错误:
request.resource是写操作(创建/更新)时才可用的对象,代表用户提交的待写入数据,读操作要获取当前文档的存储数据,需要使用resource.data,你在read规则里误用了request.resource,导致读请求匹配规则失败。 - 规则逻辑错误:逻辑运算符
&&优先级高于||,你当前的规则逻辑实际等价于(已登录且不在隐藏数组) 或 (isHiddenBy为空) 或 (isHiddenBy不等于当前用户),只要后两个条件满足,即使用户在隐藏数组中也能读取,不符合你的需求。
修复方案
1. 修正安全规则
把read规则的语法和逻辑调整为正确版本:
match /reviews/{review}{ allow read: if request.auth != null && !(request.auth.uid in resource.data.hidingUserId) && (resource.data.isHiddenBy == null || resource.data.isHiddenBy != request.auth.uid); allow delete, update, create: if request.auth != null; }
2. 修改查询代码,添加对应过滤条件
查询必须和规则匹配,添加两个过滤条件,保证查询结果只包含符合规则的文档:
// 先获取当前登录用户的uid String? currentUid = FirebaseAuth.instance.currentUser?.uid; if (currentUid == null) { // 处理未登录逻辑 return; } StreamBuilderWrapper( shrinkWrap: true, stream: postRef .where('hidingUserId', whereNotIn: [currentUid]) .where('isHiddenBy', isNotEqualTo: currentUid) .orderBy('stars', descending: true) .orderBy('timestamp', descending: true) .snapshots(), physics: NeverScrollableScrollPhysics(), itemBuilder: (_, DocumentSnapshot snapshot) { Review reviews= Review.fromJson(snapshot.data()); return reviews.postId != null // 原代码posts.postId为笔误,已修正 ? Padding( padding: const EdgeInsets.only(bottom: 12.0), child: Reviews(review: reviews), ) : Container( child: Center( child: Text('balhblahblahb'), ), ); }, ),
3. 建立复合索引
添加上述过滤和排序条件后,第一次运行会触发索引缺失的报错,你可以直接点击报错日志里的索引创建链接,跳转至Firebase控制台一键创建对应复合索引,等待索引生效后即可正常运行。
内容的提问来源于stack exchange,提问作者HaKim
相关产品推荐
相关产品推荐

