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

如何配置Firebase规则让同组织管理员读取其他用户文档?

问题

我拥有users、files等多个集合,所有集合文档均包含email和organizationId字段。需求是允许同组织内的管理员用户读取files集合中属于其他用户的文档。

当前服务端Firestore调用代码

const db = getFirestoreInstance();
...
const filesSnapshot = await db.collection("files")
  .where("email", "==", email)
  .where("organizationId", "==", organizationId)
  .orderBy("timestamp", "desc")
  .limit(filesLimit)
  .get();


...
let myApp;
if (!myApp){ myApp = initializeApp();}
let fireStoreInstance;

export const getFirestoreInstance = () => {
    if (!firestoreInstance){
       firestoreInstance = getFirestore(myApp);
    }
    return firestoreInstance;
}

当前Firebase规则代码

match /databases/{database}/documents {
    function isUserAdminInSameOrg(request, resource, database){
        let userObj = get(/databases/$(database)/documents/users/$(request.auth.token.email)).data;
        return userObj.role == 'admin' //this line works
    && userObj.organizationId == resource.data.organizationId;  //userObj.org has the correct value, resource.data.organizationId does not, despite resource.data.email working in the next function
    }

    //this function works
    function doesResourceBelongToUser(resource, request){
        return resource.data.email == request.auth.token.email;
    }
    function Rules(collection, resource, request){
        let collectionsAdminsCanRead = [
        'files'
        ];
        return (collection in collectionsAdminsCanRead && 
                    (doesResourceBelongToUser(resource, request) || isUserAdminInSameOrg(request, resource, database))) 
      || !(collection in collectionsAdminsCanRead );
    }
    match /{collection}/{document} {
      allow read: if request.auth != null && Rules(collection, resource, request);
    }
  }

规则预期逻辑:验证当前认证用户在users集合中的文档,确认其角色为admin,且该用户的organizationId与目标集合(如files)文档的organizationId一致。

已知resource.data可用于访问待查询文档字段,且在doesResourceBelongToUser函数中通过resource.data.email验证用户归属的逻辑正常,但isUserAdminInSameOrg函数中resource.data.organizationId无法获取正确值。已经知晓Firebase规则并非过滤器,且在查询中添加了where条件,请问问题出在哪里?


问题原因与修复方案

1. 查询条件限制了管理员的访问范围

当前服务端查询同时添加了where("email", "==", email)和where("organizationId", "==", organizationId),这会导致即便是管理员,也只能查询到自己的文件——email条件直接过滤掉了其他用户的文档。Firebase规则会检查查询是否与规则逻辑兼容,当管理员尝试读取其他用户的文件时,查询本身已经排除了这些文档,规则验证时自然无法获取到对应文档的organizationId。

修复方式:
服务端需要根据用户角色动态调整查询条件:

  • 普通用户:保留email和organizationId两个过滤条件;
  • 管理员:仅保留organizationId条件,去掉email过滤。

示例代码调整:

// 先从users集合获取当前用户角色
const userDoc = await db.collection("users").doc(email).get();
const userRole = userDoc.data()?.role;

// 基础查询:按组织过滤
let query = db.collection("files").where("organizationId", "==", organizationId);
// 普通用户额外添加邮箱过滤
if (userRole !== 'admin') {
  query = query.where("email", "==", email);
}

const filesSnapshot = await query.orderBy("timestamp", "desc").limit(filesLimit).get();

2. 规则中resource对象的场景限制

Firestore规则里的resource仅代表单个文档,当进行集合查询时,规则会校验"所有符合查询条件的文档都能通过规则验证"。当前查询的email条件导致管理员的查询只能匹配自己的文档,规则验证时不会触达其他用户的文档,所以resource.data.organizationId只能拿到当前用户文档的值,看起来像是"无法获取正确值"。

3. 规则逻辑优化建议

可以简化规则逻辑,直接针对files集合定义权限,同时确保规则与查询逻辑匹配:

match /databases/{database}/documents {
  // 获取当前用户的用户文档数据
  function getUserData() {
    return get(/databases/$(database)/documents/users/$(request.auth.token.email)).data;
  }

  // 判断是否为文档所有者
  function isOwner(resource) {
    return resource.data.email == request.auth.token.email;
  }

  // 判断是否为同组织管理员
  function isOrgAdmin(resource) {
    let userData = getUserData();
    return userData.role == 'admin' && userData.organizationId == resource.data.organizationId;
  }

  // 单独定义files集合的读取权限
  match /files/{document} {
    allow read: if request.auth != null && (isOwner(resource) || isOrgAdmin(resource));
  }

  // 其他集合的默认读取权限(可根据需求调整)
  match /{collection}/{document} {
    allow read: if request.auth != null;
  }
}

内容的提问来源于stack exchange,提问作者David

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 12:43:28