在Firebase Firestore中,我尝试仅允许(自定义分配的)管理员编写/更新/删除资源,为此我已经获得了以下安全规则:
service cloud.firestore {
match /databases/{database}/documents {
match /resources {
allow read;
allow write, update, delete: if get(/users/$(request.auth.uid).isAdmin);
}
match /resources/{resource} {
allow read;
allow write, update, delete: if get(/users/$(request.auth.uid).isAdmin);
}
}
}
我正在使用 users 集合中标记为管理员的用户登录:
NfwIQAjfNdS85yDvd5yPVDyMTUj2 是从身份验证窗格获取的UID:
但是,出于某种原因(确定更新:原因;请参阅答案),我在写入资源时出现 PERMISSION_DENIED 错误在绝对确定我已经与管理员用户登录后收集。
也许可以从Firestore查看请求日志?然后我可以看看request.auth.uid
看起来与我的收藏和规则相匹配的内容。
答案 0 :(得分:12)
在写我的问题时,我做到了!我犯了两个错误,如果我正确阅读文档,这两个错误都可以避免。
首先,对service-defined function get
的所有调用都需要在路径前加上 / databases / $(database)/ documents / 。所以这个规则:
allow write: if get(/users/$(request.auth.uid)).isAdmin;
成为这个:
allow write: if get(/databases/$(database)/documents/users/$(request.auth.uid)).isAdmin;
很长一段时间,我知道,但那是怎么回事。我不确定为什么Firestore本身无法做到这一点,因为看到同一路径前缀在get
的所有调用中都保持不变,但这可能是为了将来尚未准备好的功能,如跨数据库查询等。
第二次,get
函数将返回resource,而您又需要调用.data
来获取实际数据它包含。因此,而不是这样做:
get(/path/to/user/).isAdmin
你需要这样做:
get(/path/to/user/).data.isAdmin
现在我只希望能够将该逻辑提取到user-defined function:
function isAdmin() {
return get(/databases/$(database)/documents/users/$(request.auth.uid)).data.isAdmin;
}
但这样做又会导致 PERMISSION_DENIED ,并且在不知道函数中实际发生了什么的情况下,我不确定我是否会花更多时间试图解决这个问题。
更新: @Hareesh pointed out必须在匹配器的范围内定义函数,因此可以将函数放在默认的顶级匹配器中这样:
service cloud.firestore {
match /databases/{database}/documents {
function isAdmin() {
return get(/databases/$(database)/documents/users/$(request.auth.uid)).data.isAdmin == true;
}
// ...
}
}
答案 1 :(得分:3)
我注意到了一些观点
match /resources
指向一个集合,规则对其文档没有影响。在这里,我引用了doc
收藏规则不适用于该收藏品中的文件。拥有一个在集合级别而不是文档级别编写的安全规则是不寻常的(也可能是错误的)。
所以你不必为集合编写规则
然后在规则allow write, update, delete:
中,您可以说出allow write:
或具体allow create, update, delete:
这三个选项中的任何一个或将它们合并。
试试这个
service cloud.firestore {
match /databases/{database}/documents {
match /resources/{resource} {
function isAdmin() {
return get(/databases/$(database)/documents/users/$(request.auth.uid)).isAdmin ||
get(/databases/$(database)/documents/users/$(request.auth.uid)).data.isAdmin;
}
allow read;
allow create, update, delete: if isAdmin();
}
}
}