我们尝试列出“事件”集合中的所有文档。 (/event/{eventId}
)在每个事件的doc中,属性'users'(数组)在事件中存在所有用户的id。我们还有另一个集合“角色”,每个用户都扮演着每个事件的角色。 (/role/{eventId}/userRole/{userId}
)
我们有权获得一个活动
db.collection('event').doc(eventId).get()
但是当我们尝试(从android和web)进行查询时
db.collection('event').where("users", "array-contains", user.uid).get()
我们得到了FirebaseError: Missing or insufficient permissions.
活动规则:
match /event/{eventId} {
allow read:
if isAuth() &&
inEvent(eventId, request.auth.uid);
allow create:
if isAuth() &&
checkEventName() &&
isOwner(database) &&
request.resource.data.users == [];
allow update:
if isAuth() &&
resource.data.ownerId == request.auth.uid &&
checkEventName() &&
isOwner(database) &&
request.resource.data.mediaCount == resource.data.mediaCount &&
request.resource.data.users == resource.data.users;
allow delete:
if false;
}
角色规则:
match /role/{roleId} {
allow read:
if isAuth();
allow write:
if false;
match /userRole/{userRoleId} {
allow read:
if isAuth() &&
userRoleId == request.auth.uid;
allow create:
if isAuth() &&
userRoleId == request.auth.uid &&
exists(/databases/$(database)/documents/event/$(roleId)) &&
request.resource.data.actual is number &&
request.resource.data.actual >= 0 &&
request.resource.data.actual <= 10 &&
request.resource.data.previous is number &&
request.resource.data.actual == request.resource.data.previous;
allow update:
if isAuth() &&
userRoleId == request.auth.uid &&
request.resource.data.actual == 0 &&
resource.data.actual != 0;
allow delete:
if false;
}
}
角色id与事件ID匹配。
在事件的读取规则中,我们有inEvent(eventId,request.auth.uid)。当我们写作
function inEvent(eventID, userID) {
return true;
}
查询有效,但如果我们尝试类似的东西
return exists(/databases/$(database)/documents/role/$(eventID)/userRole/$(userID));
要么
return get(/databases/$(database)/documents/role/$(eventID)/userRole/$(userID)).data.actual >= 10;
我们总是得到许可错误
我们检查了所有数据和规则,但我们不明白为什么我们可以获得个别事件而不是列表。我们做错了什么?我们可以使用get()和exists()来获取列表权限吗?
首次附加侦听器时,会强制执行Firebase的安全规则。此时,服务器必须能够验证读取操作将永远只返回您有权接收的文档。在您当前的规则中,要求服务器读取每个events
文档,然后检查每个文档的用户角色。这是一个不可扩展的操作,因此服务器不允许它并拒绝读取。
这通常意味着您要保护的信息应存在于您尝试允许访问的文档(或其下的子集合)中,或存在于当前用户的固定位置。我能想到的最好的情况是在正在读取的事件下使用ACL,尽管那时我还不完全确定你是否可以建模它以便服务器可以静态评估。
另见: