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

Firebase Firestore规则编写:仅允许参与者用户访问群组数据

Firebase Firestore规则编写:按参与者权限过滤群组数据

数据结构

stage/data/groups(集合)/
       group_name
       group_id
       participants(集合)/userid

需求

  • 用户调用groups集合时,仅返回其用户ID存在于对应群组participants集合中的所有群组
  • 用户不在participants集合中的群组,无法访问

尝试过的规则

初始无效规则

rules_version = '2';    
service cloud.firestore {
  match /databases/{database}/documents {
      
    function isAuthorised(document){
      return exists(/document/participants/$(request.auth.uid))
    }
      
    match /{document=**} {
      allow read, write: if isAuthorised(document);
    }
  }
}

该规则未生效,本人熟悉ASP.NET API中遍历列表返回有效数据的方式,但作为Firebase新手,正在学习复杂的数据保护规则。

更新后的规则(硬编码群组ID时生效)

rules_version = '2';

service cloud.firestore {
  match /databases/{database}/documents {
      
      function isAuthenticated(){
        return request.auth.uid != null;
      }
      
    match /{document=**}/groups/{groupid} {
      allow read, write: if 
      isAuthenticated() && 
      exists(/databases/$(database)/documents/stage/data/groups/$(groupid)/participants/$(request.auth.uid));
    }
    
    match /{document=**}/users/{userid} {
      allow read, write: if true;
    }
  }
}

使用硬编码群组ID时规则生效,但使用$(groupid)变量时无效。

Flutter访问代码

final groupList = await ref.collection(Constants.Environment)
    .doc("data")
    .collection("groups").get();
var docs = groupList.docs.toList();

解决方案

正确的Firestore规则

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    // 验证用户已登录
    function isAuthenticated() {
      return request.auth != null && request.auth.uid != null;
    }

    // 验证用户是指定群组的参与者
    function isGroupParticipant(groupId) {
      return exists(/databases/$(database)/documents/stage/data/groups/$(groupId)/participants/$(request.auth.uid));
    }

    // 精确匹配groups集合路径
    match /stage/data/groups/{groupId} {
      // 读取权限:用户已登录且是该群组参与者
      allow read: if isAuthenticated() && isGroupParticipant(groupId);
      // 写入权限可根据实际需求调整,此处暂时与读取权限一致
      allow write: if isAuthenticated() && isGroupParticipant(groupId);
    }

    // participants子集合权限(可按需调整)
    match /stage/data/groups/{groupId}/participants/{userId} {
      allow read, write: if isAuthenticated();
    }

    // 用户集合权限保持不变
    match /stage/data/users/{userId} {
      allow read, write: if true;
    }
  }
}

关键说明与Flutter查询修改

Firestore安全规则不会自动过滤查询结果,而是验证查询是否符合权限要求。如果直接查询整个groups集合而不加过滤条件,规则会拒绝请求,因为无法确认所有返回的文档用户都有权访问。

需要修改Flutter代码,先获取用户参与的所有群组ID,再查询这些群组:

final currentUserId = FirebaseAuth.instance.currentUser?.uid;
if (currentUserId == null) {
  // 处理未登录场景
  return [];
}

// 先获取用户参与的所有群组ID
final participatingGroupIds = await getParticipatingGroupIds(currentUserId);

// 仅查询用户有权访问的群组
final groupList = await ref.collection(Constants.Environment)
    .doc("data")
    .collection("groups")
    .where(FieldPath.documentId, whereIn: participatingGroupIds)
    .get();
var docs = groupList.docs.toList();

// 辅助函数:获取当前用户参与的群组ID列表
Future<List<String>> getParticipatingGroupIds(String userId) async {
  final participantsSnapshot = await ref.collection(Constants.Environment)
      .doc("data")
      .collectionGroup("participants")
      .where(FieldPath.documentId, isEqualTo: userId)
      .get();
  // 从参与者文档路径中提取群组ID
  return participantsSnapshot.docs.map((doc) => doc.reference.parent.parent!.id).toList();
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 20:30:35