如何定义正确的Firestore Security Rules实现用户仅操作自身文档及子集合
问题解答
现有规则是否支持访问子集合文档
答案是不能。
Firestore安全规则的匹配逻辑不具备递归性,你当前编写的match /users/{userId}规则仅作用于/users/{userId}这一级的用户主文档,不会自动覆盖该文档下所有层级的子集合文档。比如路径为/users/123/orders/456的子集合文档,不会命中当前的规则,默认会被拒绝访问。
正确的规则修改方案
要实现用户可以访问自身文档下所有内容(含所有子集合),需要使用递归通配符{document=**}匹配指定路径下的所有层级文档,修改后的规则示例如下:
service cloud.firestore { match /databases/{database}/documents { match /users/{userId}/{document=**} { allow read, write: if request.auth != null && request.auth.uid == userId; } } }
上述规则中的write权限天然包含create、update、delete三类操作,也可以根据需求拆分单独声明。
需要补充的重要安全规则要点
- 修复越权创建漏洞:你原有规则中的
allow create: if request.auth != null;存在安全风险,只要是登录状态的用户,都可以创建任意uid对应的用户主文档,比如uid为1的用户可以创建/users/2的文档篡改其他用户的基础数据。必须将create的校验条件也加上request.auth.uid == userId,确保用户只能创建和自身uid匹配的文档。 - 增加字段校验逻辑:可以根据业务需求增加数据合法性校验,比如:
- 创建用户文档时校验必填字段存在:
request.resource.data.hasAll(['username', 'email']) - 校验字段值和认证信息一致:
request.resource.data.email == request.auth.token.email - 限制update操作可修改的字段范围,禁止用户自行修改会员等级、积分等敏感字段:
request.resource.data.keys().hasOnly(['avatar', 'nickname', 'signature'])
- 创建用户文档时校验必填字段存在:
- 遵循最小权限原则:如果不需要给用户删除自身数据的权限,可以单独拆分write权限,仅开放必要的read、create、update权限,关闭delete权限避免误删或恶意删数据。
- 显式声明全局默认规则:虽然Firestore默认对未匹配到规则的请求全部拒绝,但你可以显式声明全局拒绝规则让逻辑更清晰,示例如下:
service cloud.firestore { match /databases/{database}/documents { // 匹配所有用户自身的文档及子集合 match /users/{userId}/{document=**} { allow read, write: if request.auth != null && request.auth.uid == userId; } // 显式声明全局默认拒绝 match /{document=**} { allow read, write: if false; } } }
内容的提问来源于stack exchange,提问作者Dalon
相关产品推荐
相关产品推荐

