首页 > 解决方案 > 新创建文档的子集合上的“权限缺失或权限不足”

问题描述

我开发了第一个 Firestore 应用程序并没有真正意识到我没有构建权限模型,事实上我后来用螺栓固定了它。(如果这是问题的根源,我愿意接受有关权限最佳实践和/或如何更好地实施权限规则的反馈。)

作为数据模型,我在事件下方的集合中有顶级“事件”文档和“注释”文档,并且(事后)我创建了权限规则以允许在用户创建事件时编辑注释。(见下文。)

现在,在测试代码(在 iOS 上)时,应用程序会创建一个事件文档,然后很快就会尝试将快照侦听器添加到 notes 子集合。它收到“缺少权限或权限不足”错误(当然,在未强制执行权限时不会出现这种情况。)

此事件创建在列出所有事件的视图控制器中完成,然后快照侦听器查询发生在推送视图控制器中(在 segue 之后)。如果我弹出子视图控制器然后再次推送它,它会起作用。

令人困惑的是,它也不是每次都发生,它是间歇性的。我想知道权限和新创建的事件文档之间是否发生了一些竞争条件。(如果我在重试之前添加一个简短的间隔,那么下次尝试它会正常工作。)

Firebase Firestore 版本 0.13.4、Swift 4、Xcode 10.0

(编辑:实际上相同的代码在 Android 上不会失败,并且在离线时也可以工作。)

相关权限在这里:

// Access granted... via ownership
function accessGranted() {
  return resource.data.userId == request.auth.uid;
}
function accessGrantedTo(container,rootId) {
  return get(/databases/$(database)/documents/$(container)/$(rootId)).data.userId == request.auth.uid;
}

// Events...
match /events/{event} {
  allow read, update, delete: if accessGranted();
  allow create: if request.auth.uid != null;
}
match /events/{event}/notes/{note} {
  allow read, update, delete: if accessGrantedTo("events",event);
  allow create: if accessGrantedTo("events",event);
}

标签: iosgoogle-cloud-firestorefirebase-security

解决方案


上个月,我通过 Google Firebase Firestore 支持 [4-6103000026011] 探讨了这个主题。经过多次关于“对象尚不存在,等待回调等”的来回对话。它最终被提升为工程,最终解决方案是“按设计工作”。就个人而言,我认为基于设备速度的非确定性行为(有时工作,有时失败)是一种竞争条件。也就是说,也许我的方案不受支持,所以我在这里记录以防它帮助其他人。

正如我所看到的......从存储角度来看,方法调用返回后,Firestore 可能在本地完成,但其规则实现不是。这一切都很好,直到我添加了权限规则,然后事情变得不确定。

此处创建/收听的每个对象都是由该客户端中的同一客户端在本地创建的,但由于权限原因而失败,但“稍后/重试”后工作。

请记住,这可能是一个艰难的场景,我很可能通过我的要求和规则选择创造了这个问题。笔记:

  • 我无法利用 Firestore 回调,因为它们仅在设备在线且数据已同步到服务器时触发。那和(我读过)Firestore 在方法返回后本地完成,即对象在方法返回后存在,因此“无需等待回调”。[恕我直言:回调在现实世界(尤其是移动设备的间歇性在线世界)中的价值有限,我只是出于好奇而使用它们来进行故障排除。我在方法规范中看到了它们,未能深入了解它们的时间安排,并假设它们用于正常用例并在离线时被咬……而且它们没有被调用。我假设我不是唯一一个这样的开发人员。] 注意:我也不确定回调是否仅通过花费一些有限的时间来“解决”问题,
  • 我认识到这些规则是“有趣的”(使用函数来遍历层次结构)但是我使用 Firestore 的文档和示例创建了它们。(我选择不简化它们,因为支持建议将所有者属性放在较低的对象上,'因为事实上我希望进一步扩展它们以满足我的业务案例......允许团队处理数据,而不是只是创造者。)
  • 我确实认识到此代码正在创建对象 X,然后立即尝试收听我没有创建的 X 子集合的更新,即(我假设)为我创建的。我确实询问了支持人员是否有办法创建该子集合来删除那里的任何竞争条件,但这并没有作为解决方案提供。(也就是说,当不涉及这些权限规则时,这没有问题,因此它“存在”。)

长话短说,我添加了一个严重错误的“重试(有限次数),如果监听代码刚刚创建的内容并且出现权限失败错误”......并且代码似乎在第二次尝试时成功。Bugly,我并不骄傲,而是“工作”。

顺便说一句:我确实创建了一个独立的示例来重现这一点。它是 iOS(尽管 Android 也失败了,并且在 Android 提供的自动化测试虚拟机上失败最可靠。)

代码:独立 iOS 代码 - Github 存储库

规则:规则集 - Github Gist


推荐阅读