Firestore安全规则下带where查询公共集合权限不足如何解决
问题根因
报错核心原因是安全规则与查询逻辑违反了Firestore「规则不是查询过滤器」的约束,具体链路如下:
- 你在
/{root}/{doc}路径配置的读规则为root != 'ispd' && doc != 'users',该规则会拦截两类顶层文档的读请求:一是ispd根集合下的所有顶层文档,二是任意根集合下ID为users的文档。 - 你发起的是
forbidden-domains根集合的范围查询,查询语句中没有添加任何过滤条件排除ID为users的文档。 - Firestore安全规则不会在查询返回结果后再做权限过滤,只会在查询执行前校验:当前查询的约束条件能否100%保证返回的所有结果都符合权限要求。由于你的查询没有显式排除
users文档,系统判定查询可能返回无权限访问的内容,直接抛出权限不足错误,和forbidden-domains是否为公开集合无关。
解决方案
根据你的实际权限需求二选一即可:
方案1:保留现有规则逻辑,修改查询语句
如果你确实需要禁止所有用户读取任意根集合下ID为users的敏感文档,只需要在查询中显式添加文档ID过滤条件,明确告知Firestore该查询不会访问被拦截的users文档,即可通过权限校验:
// 注意先从Firestore SDK导入documentId方法,导入路径和collection/query/where保持一致 import { documentId } from 'firebase/firestore'; const checkForbiddenEmailDomain = (emailDomain) => { const collectionRef = collection(db, 'forbidden-domains'); const q = query( collectionRef, where('domain', '==', emailDomain), where(documentId(), '!=', 'users') ); return getDocs(q) .then(({ docs }) => { if (docs.length > 0) { const errorToThrown = { message: `The ${emailDomain} domain is forbidden` }; throw errorToThrown; } }); };
说明:documentId()是Firestore内置的文档ID选择器,默认自带索引,添加该过滤条件不会额外要求创建复合索引。
方案2:优化规则逻辑,缩小拦截范围
如果你实际只需要拦截ispd集合下的users文档,其他非敏感集合下的users文档不需要做读拦截,说明你原来的规则条件写了多余的拦截逻辑,直接调整规则判断条件即可,不需要修改业务查询代码:
rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { function isUserAllowed(root, metric) { return metric != 'private-data' || (metric == 'private-data' && request.auth.token.sub in get(/databases/$(database)/documents/$(root)/users).data.users); } match /{root}/{doc} { // 调整后逻辑:仅拦截ispd集合下ID为users的文档,其余顶层文档按集合属性开放读权限 allow read: if root != 'ispd' || doc != 'users'; allow write: if false; match /{metric}/{docs=**} { allow read: if isUserAllowed(root, metric); allow write: if false; } } } }
调整后规则逻辑说明:非ispd集合下的所有顶层文档(包括ID为users的文档)都允许公开读,ispd集合下仅禁止读取ID为users的文档,其余子集合权限保持原有逻辑不变。
内容的提问来源于stack exchange,提问作者Ale TheFe
相关产品推荐
相关产品推荐

