Cloud Firestore安全规则arrayUnion场景下数组大小校验疑问
Cloud Firestore arrayUnion操作下的安全规则校验逻辑说明
你当前使用request.resource.data.arr.size() < 50的写法是正确的,无需校验resource.data中的原数组长度,这个校验能生效确实是Firestore服务端对字段变换操作的内置处理机制导致的,核心逻辑如下:
- 首先明确两个规则上下文对象的本质差异:
resource.data:写入操作执行前,数据库中存储的原始文档快照request.resource.data:写入操作全部执行完成后,数据库最终要落盘的文档快照,并非客户端请求中传入的增量参数
- 客户端调用
arrayUnion、arrayRemove、increment这类字段变换方法时,虽然请求体里只带了操作符和待操作的增量值,但Firestore服务端在执行规则校验前,会先把原始文档数据和本次请求的所有字段变换做合并计算,得到操作后的完整文档状态,再基于这个最终状态生成request.resource.data供规则校验使用。 - 举个实际场景:如果原
arr数组已经有49个元素,本次调用arrayUnion追加1个不存在的新元素,服务端计算得到的request.resource.data.arr长度就是50,你的< 50规则会直接拦截请求,和你测试到的生效表现完全一致。
注意你当前的会员有效期校验存在潜在逻辑问题:
resource.data.premiumUntill > request.time读取的是操作前的旧值,如果本次更新操作会修改premiumUntill字段(比如用户续费后同步更新到期时间),这个校验会因为读到旧值出现误拦截。如果普通的数组追加操作不会修改premiumUntill字段,当前写法可以正常工作;如果要做全场景兼容,应该校验最终落盘的字段值,即改为request.resource.data.premiumUntill > request.time。
你当前使用的代码片段
客户端写入逻辑:
await updateDoc(docRef, { arr: arrayUnion(payload), }).catch((error) => { errorHandeling(error, 'An error has happened', reduxDispatch, SetSnackBarMsg); });
安全规则片段:
&& request.resource.data.arr.size() < 50 && resource.data.premiumUntill > request.time
常见误区提醒
不要改用resource.data.arr.size() < 50做长度校验:这个值是操作前的数组长度,比如原数组已经有49个元素时,校验原长度会直接放行请求,但追加元素后数组实际长度就达到50,完全达不到限制最终数组长度的目的。
内容的提问来源于stack exchange,提问作者Richardson
相关产品推荐
相关产品推荐

