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

Firestore规则无法读取现有数据,求排查权限拒绝原因

Firestore权限拒绝问题解决

问题背景

Firestore数据库中文档包含playerCount = 1(整数类型)和isStarted = true(布尔类型)字段,使用以下规则时,Android端执行指定查询始终返回Permission Denied,无法读取resource.data.isStarted和resource.data.playerCount。

当前Firestore规则

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
  
    match /props/{propId} {
        allow list,write,create: if false;
        allow read: if isLoggedIn() && propId=="7Ia********iqDO";
    }
    
    match /rooms/{roomId=**} {
        allow create: if isLoggedIn();
      allow read, list: if roomData("KjUXL49I1XVlXDGZ8jqL").playerCount==1 || resource.data.playerCount == 1 || oldData().isStarted || authData().uid in oldData().accessIds;
      allow write: if authData().uid in oldData().accessIds;
    }
  }
  
  function isLoggedIn() { return authData() != null;}
  function authData() { return request.auth }
  function oldData() { return resource.data }
    function newData() { return request.resource.data }
  function roomData(roomPath) { return get(/databases/$(database)/documents/rooms/$(roomPath)).data }

}

Android查询代码

FirebaseFirestore.getInstance().collection("rooms").whereEqualTo("roomId", "023340").limit(1).get(Source.SERVER).addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
                                        @Override
                                        public void onComplete(@NonNull Task<QuerySnapshot> task) {
                                            if(task.isSuccessful()){
                                                ArrayList a = (ArrayList)task.getResult().getDocuments().get(0).getData().get("accessIds");
                                                Log.d("sdccddsdcswc", String.valueOf(a.size()));
                                            } else {
                                                toast("Failed to read Room");
                                            }
                                        }
                                    });

问题原因

  1. 自定义函数混淆概念
    你定义的oldData()函数指向resource.data,但读取规则中resource.data本身就代表数据库中现有文档的数据,额外封装不仅冗余,还容易引发逻辑误解。读取操作中不存在request.resource,直接使用resource.data即可访问文档字段。

  2. 规则与查询逻辑不匹配
    Firestore规则采用集合级过滤机制,要求规则能验证所有符合查询条件的文档都满足权限要求。你的查询是按roomId=023340过滤,但规则中未关联该查询条件;同时硬编码的roomData("KjUXL49I1XVlXDGZ8jqL")仅验证特定文档的playerCount,与目标查询文档无关。

  3. 读取条件逻辑缺陷
    规则中的oldData().isStarted实际等同于resource.data.isStarted,但规则引擎无法在集合层面验证所有符合roomId=023340的文档都满足playerCount=1、isStarted=true或用户在accessIds中,因此直接拒绝整个查询。

修正方案

调整后的Firestore规则

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
  
    match /props/{propId} {
        allow list,write,create: if false;
        allow read: if request.auth != null && propId=="7Ia********iqDO";
    }
    
    match /rooms/{roomId} {
        allow create: if request.auth != null;
        // 读取规则:已登录用户,且满足任一权限条件
        allow read, list: if request.auth != null && (
            resource.data.playerCount == 1 ||
            resource.data.isStarted == true ||
            request.auth.uid in resource.data.accessIds
        );
        allow write: if request.auth.uid in resource.data.accessIds;
    }
  }
}

关键修改点

  • 移除冗余自定义函数,直接使用Firestore原生变量request.auth和resource.data,避免概念混淆
  • 简化读取规则逻辑,明确验证当前文档的字段状态或用户权限
  • 去掉rooms匹配规则中的=**,仅匹配rooms集合下的一级文档(若无需子集合权限控制)

额外验证步骤

  • 确认查询目标文档roomId=023340确实存在playerCount=1、isStarted=true,或当前登录用户的UID在accessIds列表中
  • 测试时可临时放宽规则(如allow read: if request.auth != null;)验证是否为规则问题,之后再恢复严格权限

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 20:25:17