Firestore安全规则:如何从父文档获取resource.data.userID?
解决Firestore子集合权限验证:从父文档读取userID
没问题,完全可以通过父文档的userID字段来验证子集合的访问权限!你遇到的问题确实是因为history子集合里的文档本身没有userID,导致原来的规则里针对子文档的验证无法通过——毕竟子文档里根本没有这个字段嘛。
问题根源
你原来的规则用了match /scores/{docID=**}这种递归匹配,会覆盖scores下所有层级的文档(包括子集合)。但对于history里的文档来说:
- 读取时,
resource.data.userID不存在,验证失败 - 创建/更新时,
request.resource.data.userID也不存在(你不会给子文档加这个字段),同样验证失败
所以我们需要拆分规则,单独处理子集合,通过父文档的userID来做权限校验。
修改后的安全规则
首先假设你已经定义了userIsLoggedIn()函数(和你原来的规则一致):
function userIsLoggedIn() { return request.auth != null; }
接下来是核心规则,我们分开匹配父文档和子集合:
// 匹配scores下的根文档 match /scores/{scoreDocID} { allow read: if userIsLoggedIn(); allow create, update: if request.resource.data.userID == request.auth.uid; allow delete: if resource.data.userID == request.auth.uid; // 匹配history子集合的所有文档 match /history/{historyDocID} { // 读取子集合:验证父文档的所有者是当前登录用户 allow read: if userIsLoggedIn() && get(/databases/$(database)/documents/scores/$(scoreDocID)).data.userID == request.auth.uid; // 创建/更新子集合:同样验证父文档归属 allow create, update: if userIsLoggedIn() && get(/databases/$(database)/documents/scores/$(scoreDocID)).data.userID == request.auth.uid; // 删除子集合:验证父文档归属 allow delete: if userIsLoggedIn() && get(/databases/$(database)/documents/scores/$(scoreDocID)).data.userID == request.auth.uid; } }
规则解释
- 拆分匹配层级:把父文档和子集合的规则分开写,避免递归匹配带来的字段缺失问题
- 通过
get()获取父文档数据:利用scoreDocID参数定位到对应的父scores文档,读取它的userID字段,验证当前用户是否是该文档的所有者 - 统一权限逻辑:子集合的所有操作(读、写、删)都依赖父文档的权限,确保只有父文档的所有者才能操作对应的子集合数据
优化:抽成复用函数
如果觉得重复写get(...)太繁琐,可以把父文档的权限校验抽成一个函数,让规则更简洁:
function userIsLoggedIn() { return request.auth != null; } function isScoreOwner(scoreDocID) { return get(/databases/$(database)/documents/scores/$(scoreDocID)).data.userID == request.auth.uid; } match /scores/{scoreDocID} { allow read: if userIsLoggedIn(); allow create, update: if request.resource.data.userID == request.auth.uid; allow delete: if resource.data.userID == request.auth.uid; match /history/{historyDocID} { allow read, create, update, delete: if userIsLoggedIn() && isScoreOwner(scoreDocID); } }
这样修改后,用户就能正常访问自己所属scores文档下的history子集合了。
内容的提问来源于stack exchange,提问作者KevinB
相关产品推荐
相关产品推荐

