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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 16:40:18