You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Firestore安全规则咨询:双人互认伙伴文档权限配置优化

优化Firestore伙伴共享文档的安全规则方案

咱们先拆解下你遇到的问题,再一步步给出更靠谱的实现方案:

你原有规则的问题分析

  1. 第一个规则的逻辑漏洞
    你最初写的partnersId.contains(request.auth.uid)看起来简单,但存在致命逻辑漏洞:比如如果有个文档ID是JoeSmith,用户Joe也能访问这个文档,但Smith未必是他的正式伙伴,完全不符合你「仅互为伙伴的用户才能访问」的需求。另外如果用户UID包含特殊字符,拼接后也可能出现误匹配的情况。

  2. 第二个规则的成本与语法问题
    你构思的第二次规则不仅语法有误(比如未定义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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.08 20:12:42