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

Firestore子集合与集合组查询的安全规则配置问题

问题:Firestore子集合查询权限配置问题

数据结构

Users
 - w34rj3d9d2383
   - name
   - email
   - items (sub-collection)
     - dj23jd23wkjdkl
       - name
       - notes
       - createdBy
     - 4ru328rjwiodj2309
       - name
       - notes
       - createdBy

问题描述

当前在现有安全规则下,能指定userId和itemId订阅已认证用户的items子集合单个条目,也能不添加谓词获取指定用户所有items,但添加谓词查询时无结果返回。

Swift查询代码

let path = "users/w34rj3d9d2383/items"
let predicate = NSPredicate(format: "SELF.name CONTAINS %@", name)
let collectionReference = Firestore.firestore().collection(path).filter(using: predicate)
collectionReference.addSnapshotListener(includeMetadataChanges: false) { querySnapshot, error in
    //...
}

现有安全规则

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {

    match /users/{userId} {
      allow read, update, delete: if request.auth != null && request.auth.uid == userId;
      allow create: if request.auth != null;
    }
    
    match /users/{userId}/{document=**}{
      allow read, update, delete: if request.auth != null && request.auth.uid == userId;
      allow create: if request.auth != null;
    }
  }
}

更新记录

更新1

尝试以下操作仍有权限问题:

  1. 将引用改为集合组:
let collectionReference = Firestore.firestore().collectionGroup("items").filter(using: predicate)
  1. 规则中添加:
match /{path=**}/items/{itemId} {
    allow list: if request.auth.uid == resource.data.createdBy;
    allow get: if request.auth.uid == resource.data.createdBy;
}

更新2

使用以下规则成功实现查询,但权限过宽:

match /{path=**}/items/{itemId} {
    allow read, write: if request.auth != null;
}

此规则下,集合组查询能获取所有items,但希望仅返回resource.data.createdBy与request.auth.uid匹配的条目,添加该验证条件时系统提示resource为null,求解决方法。


解决方案

问题根源

用集合组查询时,Firestore安全规则执行list操作权限检查时,会先验证整个查询而非逐个文档,此时resource对象仅在单个文档的get操作中有效,list(多文档查询)时resource为null,这就是报错原因。

正确配置方式

分两种场景处理:

1. 仅查询当前用户自己的items子集合

无需用集合组,直接保留原路径,原规则已经满足权限要求。如果查询仍无结果,检查:

  • 当前认证用户的uid是否确实等于w34rj3d9d2383
  • 谓词中的name参数是否正确,是否存在匹配的文档

2. 集合组跨用户查询(仅返回自己创建的条目)

需要同时验证查询条件和用户身份,确保查询必须包含createdBy == 当前用户uid的过滤逻辑:

修改安全规则:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    // 保留原用户文档规则
    match /users/{userId} {
      allow read, update, delete: if request.auth != null && request.auth.uid == userId;
      allow create: if request.auth != null;
    }
    
    // 保留单个用户子集合规则
    match /users/{userId}/{document=**}{
      allow read, update, delete: if request.auth != null && request.auth.uid == userId;
      allow create: if request.auth != null;
    }

    // 集合组查询的items规则
    match /{path=**}/items/{itemId} {
      // 单个文档查询:验证createdBy匹配当前用户
      allow get: if request.auth != null && request.auth.uid == resource.data.createdBy;
      // 多文档查询:强制查询必须包含createdBy等于当前用户的条件
      allow list: if request.auth != null 
                   && request.query.where('createdBy', '==', request.auth.uid);
    }
  }
}

修改Swift查询代码,必须添加createdBy过滤条件:

guard let currentUid = Auth.auth().currentUser?.uid else { return }
let nameFilter = NSPredicate(format: "SELF.name CONTAINS %@", name)
let userFilter = NSPredicate(format: "createdBy == %@", currentUid)
let combinedPredicate = NSCompoundPredicate(andPredicateWithSubpredicates: [nameFilter, userFilter])

let collectionReference = Firestore.firestore().collectionGroup("items").filter(using: combinedPredicate)
collectionReference.addSnapshotListener(includeMetadataChanges: false) { querySnapshot, error in
    //...
}

关键说明

Firestore安全规则不会自动过滤数据,只会验证查询是否符合权限要求。如果规则要求查询必须包含createdBy == 当前用户,代码必须显式添加该条件,否则规则会直接拒绝整个查询。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 21:40:16