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

iOS App运行时Firestore安全规则失效,快照监听器执行两次

Firestore快照监听器执行两次且第二次读取失败的问题排查与解决

问题原因分析

  • 监听器两次触发的本质:Firestore快照监听器默认先返回本地缓存的文档数据(第一次触发),随后向服务器请求最新数据并验证权限(第二次触发),这是Firestore离线缓存机制的正常设计,并非Bug。
  • 安全规则权限不匹配:你的安全规则要求request.auth.uid == resource.data.userId,即仅当文档内userId字段值与当前登录用户UID一致时才允许读写。第二次触发时服务器验证权限不通过导致读取失败,但代码未处理错误场景,因此表现为“无法读取”。

修复步骤

1. 修正安全规则(根据业务需求二选一)

如果你的users集合文档ID本身就是用户UID(Firestore常见设计),直接匹配文档ID而非文档内字段更合理,规则修改为:

service cloud.firestore {
  match /databases/{database}/documents {
  
    match /users/{userId} {
        allow read, write: if request.auth.uid == userId;
    }

  }
}

若必须基于文档内userId字段做权限控制,需确保:

  • 当前登录用户UID与目标文档的userId字段值完全一致
  • 目标文档确实存在userId字段且未出现拼写错误

2. 完善代码的错误处理

原代码仅忽略错误未做日志输出,无法排查权限问题,修改后代码:

Firestore.firestore().collection("users").document("CVDYKKxjLHa69RgWqLxwwnEHHCj2").addSnapshotListener { snapshot, error in
    if let error = error {
        print("监听文档出错:\(error.localizedDescription)")
        return
    }

    guard let snapshot = snapshot, snapshot.exists else {
        print("文档不存在或无访问权限")
        return
    }

    self.counter += 1
    print(self.counter)
    // 处理文档数据
    let userData = snapshot.data()
    print("用户数据:\(userData ?? [:])")
}

添加错误打印后,可在控制台直接查看权限拒绝的具体原因,辅助定位问题。

3. 验证用户登录状态

确保添加监听器前用户已完成Firebase Auth登录,避免request.auth为空导致权限验证失败,可在代码前添加检查:

guard let currentUser = Auth.auth().currentUser else {
    print("用户未登录")
    return
}
print("当前登录用户UID:\(currentUser.uid)")

额外说明

  • 安全规则设为“开放”时,服务器跳过权限验证,因此两次触发都能正常读取,这也验证了问题根源是权限规则不匹配。
  • 监听器的两次触发是离线缓存机制的正常表现,后续文档更新时监听器还会继续触发。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 18:52:46