为何Firestore已配置list权限仍返回permission-denied错误?
问题描述
我配置了如下Firestore规则:
rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { function isAuthenticated() { return request.auth.uid != null; } function ownsData(id) { return request.auth.uid == id; } match /feedpoints/{fid} { allow read: if request.auth != null; } match /feedpoints/{fid} { allow write: if false; } match /profiles { allow list: if false; match /{pid} { allow read: if isAuthenticated() && request.auth.uid == pid; } match /subscriptions { allow list: if isAuthenticated(); match /{sid} { allow read, write, list: if isAuthenticated() && ownsData(sid); } } match /bookmarks { allow list: if isAuthenticated(); match /{bid} { allow read, write, list: if isAuthenticated() && ownsData(bid); } } } } }
尝试列出/profiles/{pid}/subscriptions下的所有文档时,Flutter应用始终收到错误:
[cloud_firestore/permission-denied] The caller does not have permission to execute the specified operation.
相关日志:
Listen for Query(target=Query(profiles/qguefZV3SjOpf1CGdIJrmufoUBPK/subscriptions order by name);limitType=LIMIT_TO_FIRST) failed: Status{code=PERMISSION_DENIED, description=No matching allow statements, cause=null}
使用Firebase模拟器测试,明明已在match /subscriptions下设置allow list: if isAuthenticated(),为何仍权限拒绝?
问题原因
你的Firestore规则路径匹配错误。当前match /subscriptions是直接嵌套在match /profiles下,对应的实际路径是/profiles/subscriptions,但你要访问的是/profiles/{pid}/subscriptions——也就是每个用户pid文档下的subscriptions子集合,两者路径不匹配,导致规则不生效。
修正方案
将subscriptions和bookmarks的匹配规则嵌套到match /{pid}内部,确保路径层级正确:
rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { function isAuthenticated() { return request.auth.uid != null; } function ownsData(id) { return request.auth.uid == id; } match /feedpoints/{fid} { allow read: if request.auth != null; allow write: if false; } match /profiles { allow list: if false; match /{pid} { allow read: if isAuthenticated() && request.auth.uid == pid; // 将subscriptions和bookmarks嵌套到{pid}层级下 match /subscriptions { allow list: if isAuthenticated(); match /{sid} { allow read, write, list: if isAuthenticated() && ownsData(sid); } } match /bookmarks { allow list: if isAuthenticated(); match /{bid} { allow read, write, list: if isAuthenticated() && ownsData(bid); } } } } } }
补充说明
Firestore规则的路径匹配是精确层级匹配,每个match语句对应一个路径段。如果要匹配/profiles/{pid}/subscriptions,必须让subscriptions的match作为/{pid}的子规则,这样才能正确对应到用户文档下的子集合路径。
内容的提问来源于stack exchange,提问作者Eray Erdin

