Firestore规则权限异常:自定义声明用户查询权限被拒
Firestore规则配置解决方案
问题1:Customers集合查询权限被拒
Firestore安全规则的核心要求是查询必须与权限条件完全匹配——也就是说,规则得能验证查询返回的每一个文档都符合权限要求。你之前的规则只校验单个文档的路径匹配,但查询时用了tenantID过滤,规则无法自动关联tenantID和用户的自定义声明,导致Firestore无法确认所有返回文档都满足权限,直接拒绝查询。
修正后的Customers集合规则
rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { // 复用权限逻辑:判断用户是否有权访问指定customerId function canAccessCustomer(customerId) { return request.auth != null && ( request.auth.token.customerId == customerId || customerId in request.auth.token.customerIds ); } // 覆盖Customers集合及所有嵌套文档(包括People这类子集合) match /Customers/{customerId}/{document=**} { allow read, write: if canAccessCustomer(customerId); } // 集合查询权限补充:强制查询逻辑与权限匹配 match /Customers/{customerId} { allow list: if canAccessCustomer(customerId) && request.query.where('tenantID', '==', resource.data.tenantID); } } }
关键说明
- 用
canAccessCustomer函数把权限逻辑抽出来,避免重复代码 - 集合查询时,Firestore需要确认所有返回文档都符合权限,所以规则里强制要求查询必须带
tenantID过滤,且该过滤条件和文档实际的tenantID一致 - 客户端已经加了
tenantID过滤,但规则必须显式校验这个条件和权限的关联,否则Firestore会认为查询可能返回无权限文档
问题2:Customer/{customerId}/People集合无法访问
你之前的规则大概率没覆盖嵌套集合的权限,或者没正确继承父文档的customerId参数。上面的规则用{document=**}通配符,已经覆盖了Customers/{customerId}下的所有嵌套集合(包括People)——只要用户能访问父级的customerId,就能访问其下所有嵌套文档。如果还是不行,检查这几点:
- 客户端打印用户的自定义声明,确认
customerId确实存在且正确(用await getAuth().currentUser.getIdTokenResult()可以查看) - 确认People集合的路径是
Customers/{customerId}/People/{personId},规则的通配符能匹配到 - 如果需要额外权限控制(比如People文档的特定字段),可以单独加规则:
match /Customers/{customerId}/People/{personId} { allow read, write: if canAccessCustomer(customerId) && resource.data.ownerId == request.auth.uid; // 示例:仅允许文档所有者操作 }
问题3:Sites集合权限修正
针对Sites集合的双重权限条件,规则需要同时校验用户自定义声明和文档的permissionsToView数组,还要处理集合查询的情况:
// Sites集合及嵌套文档权限 match /Sites/{siteId}/{document=**} { allow read, write: if request.auth != null && ( // 条件1:用户sites数组包含siteId,且文档允许该用户的customerId查看 (request.auth.token.sites has siteId && request.auth.token.customerId in resource.data.permissionsToView) || // 条件2:文档直接允许该用户的customerId查看 request.auth.token.customerId in resource.data.permissionsToView ); } // Sites集合查询权限补充 match /Sites/{siteId} { allow list: if request.auth != null && ( (request.auth.token.sites has siteId && request.auth.token.customerId in resource.data.permissionsToView) || request.auth.token.customerId in resource.data.permissionsToView ); }
客户端查询优化建议
针对Customers集合的查询,你可以在客户端加上用户有权访问的customerId过滤,既减少无权限文档的返回,也让Firestore规则更容易验证:
const user = await getAuth().currentUser; const tokenResult = await user.getIdTokenResult(); const customerFilters = []; if (tokenResult.claims.customerId) { customerFilters.push(where("customerId", "==", tokenResult.claims.customerId)); } if (tokenResult.claims.customerIds) { customerFilters.push(where("customerId", "in", tokenResult.claims.customerIds)); } const customersQuery = query( collection(db, "Customers"), where("tenantID", "==", tenantID), ...customerFilters ); const docs = await getDocs(customersQuery);
内容的提问来源于stack exchange,提问作者AndreCoelhoo
相关产品推荐
相关产品推荐

