"Missing or insufficient permissions"新创建的文档的子集合



我开发了第一个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);
}

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

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

这里创建/侦听的每个对象都是由该客户端中的同一客户端在本地创建的,但由于权限原因而失败,但"稍后/重试"即可工作。

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

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

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

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

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

规则:规则集-Github Gist

最新更新