Firestore安全规则:基于数组字段管控父文档与嵌套集合权限
解决方案
核心思路
利用Firestore规则的get()方法获取父级accounts文档验证权限,同时强制查询携带accountId in条件,确保规则仅验证用户有权访问的账户ID,避免无差别遍历父文档导致的性能或规则拒绝问题。
安全规则实现
// 判断是否为拥有全权限的管理员 function isAdmin() { // 根据你的实际admin配置调整,示例为检查邮箱是否在admins集合中 return exists(/databases/$(database)/documents/admins/$(request.auth.token.email)); } // 验证用户是否有权访问指定账户 function canAccessAccount(accountId) { if (isAdmin()) return true; const accountRef = /databases/$(database)/documents/accounts/$(accountId); return exists(accountRef) && get(accountRef).data.users.hasAny([request.auth.token.email]); } // 针对projects集合组的读取规则 match /{document=**}/projects/{project} { allow read: if request.auth != null && ( isAdmin() || ( // 强制查询必须包含accountId的in过滤条件 'accountId' in request.query && request.query.accountId.op == 'in' && // 验证查询列表中的每个accountId用户都有权访问 request.query.accountId.value.every(accountId => canAccessAccount(accountId)) && // 最终校验当前项目对应的账户确实是用户有权访问的 canAccessAccount(resource.data.accountId) ) ); }
关键说明
- 权限复用:通过
isAdmin和canAccessAccount函数复用现有权限逻辑,避免规则冗余。 - 查询强制校验:要求查询必须携带
accountId in条件,确保规则仅处理用户预先筛选的账户ID,大幅降低权限验证的开销。 - 双重验证:既校验查询列表的合法性,又单独校验当前项目的账户权限,防止恶意构造查询绕过规则。
前端代码注意事项
你当前的查询代码无需修改:
this.firestore.collectionGroup('projects', (ref) => ref.where('accountId','in',accountIds)).get()
只需确保accountIds是前端从accounts集合中预先查询到的、包含当前用户邮箱的文档ID数组,这样就能和规则形成完整的权限闭环。
内容的提问来源于stack exchange,提问作者Frank Packer
相关产品推荐
相关产品推荐

