Firestore安全规则咨询:双人互认伙伴文档权限配置优化
优化Firestore伙伴共享文档的安全规则方案
咱们先拆解下你遇到的问题,再一步步给出更靠谱的实现方案:
你原有规则的问题分析
第一个规则的逻辑漏洞
你最初写的partnersId.contains(request.auth.uid)看起来简单,但存在致命逻辑漏洞:比如如果有个文档ID是JoeSmith,用户Joe也能访问这个文档,但Smith未必是他的正式伙伴,完全不符合你「仅互为伙伴的用户才能访问」的需求。另外如果用户UID包含特殊字符,拼接后也可能出现误匹配的情况。第二个规则的成本与语法问题
你构思的第二次规则不仅语法有误(比如未定义partneruid变量,data.$(request.auth.uid)这种字段访问方式在Firestore规则里不合法,正确写法是data[request.auth.uid]),还包含3次读取操作,这会显著增加Firestore的规则执行成本,也更容易出错。
更优的实现方案
我们可以通过减少读取次数+明确文档ID规则来优化,同时确保双向伙伴确认的逻辑。
方案一:兼容两种文档ID组合(JoeMary/MaryJoe)
这个方案允许文档ID是两个UID的任意拼接顺序,规则逻辑如下:
rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { match /partners/{partnerDocId} { // 允许读取、更新、删除:用户已认证,且文档ID是自己与伙伴UID的组合 allow read, update, delete: if request.auth != null && let currentUser = request.auth.uid, // 获取当前用户的伙伴UID partnerUid = get(/databases/$(database)/documents/users/$(currentUser)).data.partner; // 确保伙伴存在,且文档ID是两种合法组合之一 partnerUid != null && (partnerDocId == currentUser + partnerUid || partnerDocId == partnerUid + currentUser); // 允许创建:确保双向伙伴确认,且文档ID合法、数据一致 allow create: if request.auth != null && let currentUser = request.auth.uid, partnerUid = get(/databases/$(database)/documents/users/$(currentUser)).data.partner; // 伙伴存在,且伙伴的partner字段也指向当前用户(双向确认) partnerUid != null && get(/databases/$(database)/documents/users/$(partnerUid)).data.partner == currentUser && // 文档ID是合法组合之一 (partnerDocId == currentUser + partnerUid || partnerDocId == partnerUid + currentUser) && // 文档数据包含两个用户的标识(确保数据一致性) request.resource.data[currentUser] == true && request.resource.data[partnerUid] == true; } } }
方案二:强制固定顺序的文档ID(推荐)
为了避免出现JoeMary和MaryJoe两个重复文档,我们可以强制文档ID按UID字典序排序拼接(比如用下划线分隔),比如Joe_Mary(假设Joe的UID字典序小于Mary)。这种方式能进一步简化规则:
rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { match /partners/{partnerDocId} { allow read, update, delete: if request.auth != null && let currentUser = request.auth.uid, partnerUid = get(/databases/$(database)/documents/users/$(currentUser)).data.partner; partnerUid != null && // 生成固定顺序的合法文档ID partnerDocId == min(currentUser, partnerUid) + "_" + max(currentUser, partnerUid); allow create: if request.auth != null && let currentUser = request.auth.uid, partnerUid = get(/databases/$(database)/documents/users/$(currentUser)).data.partner; partnerUid != null && get(/databases/$(database)/documents/users/$(partnerUid)).data.partner == currentUser && partnerDocId == min(currentUser, partnerUid) + "_" + max(currentUser, partnerUid) && request.resource.data[currentUser] == true && request.resource.data[partnerUid] == true; } } }
方案优势
- 更低的执行成本:读写删操作仅需1次读取(获取当前用户的伙伴),创建操作仅需2次读取(确认双向伙伴关系),远低于你之前的3次读取。
- 逻辑严谨:确保只有互为伙伴的用户才能访问对应文档,避免了原规则的逻辑漏洞。
- 数据一致性:创建规则里强制校验文档数据与伙伴关系的匹配,避免无效数据的生成。
内容的提问来源于stack exchange,提问作者Xiiryo
相关产品推荐
相关产品推荐

