You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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;
  }
}

规则解释

  1. 拆分匹配层级:把父文档和子集合的规则分开写,避免递归匹配带来的字段缺失问题
  2. 通过get()获取父文档数据:利用scoreDocID参数定位到对应的父scores文档,读取它的userID字段,验证当前用户是否是该文档的所有者
  3. 统一权限逻辑:子集合的所有操作(读、写、删)都依赖父文档的权限,确保只有父文档的所有者才能操作对应的子集合数据

优化:抽成复用函数

如果觉得重复写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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:03:46