Firestore基于角色的访问规则失效,请求排查原因
问题背景
我要给Firebase Cloud Firestore配置规则,只让登录且角色是admin的用户访问users集合(该集合仅存储姓名和年龄)。数据库包含两个集合:
- Roles集合:文档ID与用户UID一一对应,每个文档包含
role字段,值可设为admin; - Users集合:仅对登录的管理员用户开放访问权限。
我编写的规则如下:
rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { match /users/{document} { allow read: if get(/databases/$(database)/documents/roles/$(request.auth.id)/role) == "admin" } } }
使用Firebase控制台规则模拟器测试时,我以已认证的管理员用户身份访问路径/users/RaafvyRPWYuN3IyqdoBa(users集合中的某文档ID),却收到“模拟读取被拒绝”的提示,请求分析规则不生效的原因。
问题原因拆解
get()返回值处理错误get()方法返回的是文档快照对象,并非直接的字段值。直接将该对象与字符串"admin"比较,结果永远为false——因为对象和字符串无法直接相等。正确的做法是通过.data.role提取字段值。缺少登录状态校验
规则中未先验证用户是否已登录(request.auth != null)。若用户未登录,request.auth.id会是null,调用get()时会直接报错,导致规则拒绝访问。即便测试用的是已登录用户,添加该校验也能避免潜在错误,同时符合“仅允许登录用户”的需求。未处理Roles文档不存在的情况
若登录用户在Roles集合中没有对应文档,get()方法会抛出错误,规则同样会拒绝访问。应先用exists()检查文档是否存在,再获取字段值。废弃字段使用问题
当前Firestore规则中,request.auth.id已被废弃,正确获取用户ID的字段是request.auth.uid。若你的Firebase版本较新,使用id将无法拿到正确的用户ID,这也会导致规则判断错误。
修正后的规则
rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { match /users/{document} { allow read: if request.auth != null && exists(/databases/$(database)/documents/roles/$(request.auth.uid)) && get(/databases/$(database)/documents/roles/$(request.auth.uid)).data.role == "admin"; } } }
测试注意事项
- 确认Roles集合中存在测试用户UID对应的文档,且
role字段的值为字符串类型的"admin"(规则大小写敏感,请勿写成Admin或ADMIN); - 模拟器测试时,需正确填写用户的UID,确保与Roles集合中的文档ID一致。
内容的提问来源于stack exchange,提问作者Stone Cutter

