如何编写Firestore规则适配带共享子项的多用户树形数据结构
Firestore权限规则实现方案
需求回顾
artifacts集合的文档按树形结构组织:
- 根节点的
parentId为null,包含usersIds数组定义有权限的用户 - 子节点的
parentId指向父节点ID,权限完全继承根节点,子节点无法自定义权限 - 仅根节点的
usersIds内的用户可访问该根节点及其所有子节点
实现方案:递归函数验证
Firestore安全规则支持自定义递归函数,可以通过递归向上遍历父节点,找到根节点后验证用户权限。
规则代码
rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { // 递归验证用户是否有权访问当前文档的根节点 function hasRootPermission(docRef) { let doc = docRef.get(); // 找到根节点,检查用户是否在授权列表中 if (doc.data.parentId == null) { return request.auth != null && doc.data.usersIds.has(request.auth.uid); } // 未找到根节点,递归检查父节点 else { let parentDocRef = /databases/$(database)/documents/artifacts/$(doc.data.parentId); return hasRootPermission(parentDocRef); } } // 匹配artifacts下所有文档,应用权限规则 match /artifacts/{artifactId} { allow read, write: if hasRootPermission(resource); } } }
注意事项
Firestore安全规则的递归调用存在最大深度限制(10层),如果你的树形结构层级超过10层,递归会触发规则验证失败,此时需要使用优化方案。
优化方案:冗余存储根节点ID
为避免递归深度限制,推荐在每个artifact文档中添加rootArtifactId字段,直接存储根节点的ID,这样无需递归,直接通过该字段定位根节点验证权限。
文档示例(添加rootArtifactId后)
{ id: 'a', parentId: null, usersIds: ['joe', 'jane'], rootArtifactId: 'a' } { id: 'a1', parentId: 'a', rootArtifactId: 'a' } { id: 'a11', parentId: 'a1', rootArtifactId: 'a' } { id: 'b', parentId: null, usersIds: ['mary'], rootArtifactId: 'b' } { id: 'b1', parentId: 'b', rootArtifactId: 'b' }
优化后的规则代码
rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { // 直接通过根节点ID验证权限 function hasRootPermission() { let rootDocRef = /databases/$(database)/documents/artifacts/$(resource.data.rootArtifactId); return request.auth != null && rootDocRef.get().data.usersIds.has(request.auth.uid); } match /artifacts/{artifactId} { allow read, write: if hasRootPermission(); } } }
优势
- 避免递归深度限制,支持任意层级的树形结构
- 规则验证性能更高,无需多次遍历父节点
内容的提问来源于stack exchange,提问作者João Melo
相关产品推荐
相关产品推荐

