Firestore离线排队请求中request.time赋值时机及安全规则验证问题
Firestore离线场景下的用户创建规则验证问题
我正在编写Firestore数据库的用户创建验证规则,用户文档包含由客户端设置的dateCreated Firestore时间戳字段。我希望仅允许dateCreated字段为合理值的用户创建(不能为去年或上月的时间),计划通过与request.time对比实现验证,规则代码如下:
service cloud.firestore { match /databases/{database}/documents { match /users/{userId} { // VALIDATE USER // Allow create if request is authenticated, and the uid and docId of the user being // created matches the auth uid allow create: if request.auth != null && request.auth.uid == request.resource.data.userId && request.auth.uid == request.resource.id // VALIDATE FIELDS && request.resource.data.keys().hasAny(["dateCreated"]) && resource.data.dateCreated <= request.time && resource.data.dateCreated + duration.value(60, 'm') >= request.time; } }
同时我需要支持数据库离线使用。若用户在飞行模式下发起用户创建请求,该请求会自动在设备本地队列排队,恢复网络后再发送至服务器。现咨询:
- 对于排队的离线请求,
request.time是在加入本地队列时赋值,还是在到达服务器时赋值? - 若
request.time为服务器接收时间,会导致dateCreated与request.time差值过大,验证规则失效,此场景下该规则是否可行?
问题解答
1. request.time的赋值时机
request.time是请求到达Firestore服务器时的时间戳,和请求在本地队列排队的时间无关。无论用户是在线直接提交,还是离线排队后恢复网络提交,这个值都是服务器实际处理请求的时间。
2. 当前规则的可行性分析
当前规则不可行,主要有两个问题:
- 离线场景下,客户端设置的
dateCreated是排队时的本地时间,等到恢复网络提交到服务器时,两者的时间差很可能超过你设置的60分钟阈值,直接触发验证失败。 - 规则代码存在逻辑错误:创建请求阶段还不存在
resource对象,resource.data.dateCreated应该改为request.resource.data.dateCreated,否则规则本身会报错无法正常运行。
优化方案
如果要兼容离线场景,同时保证dateCreated的合理性,可以调整验证逻辑:
- 放宽时间范围:比如允许
dateCreated在服务器时间的前后24小时内,给离线排队留出足够的缓冲空间。 - 由服务器生成时间戳:使用Firestore的服务器时间戳(
serverTimestamp()),客户端不设置dateCreated字段,规则里强制dateCreated等于request.time,这样不管离线排队多久,最终存储的都是服务器处理时间,也能避免客户端篡改时间。
调整后的示例规则(使用服务器时间戳):
service cloud.firestore { match /databases/{database}/documents { match /users/{userId} { allow create: if request.auth != null && request.auth.uid == request.resource.data.userId && request.auth.uid == request.resource.id && request.resource.data.dateCreated == request.time; } }
内容的提问来源于stack exchange,提问作者Reagankm
相关产品推荐
相关产品推荐

