我正在对以下Firestore安全规则进行单元测试,该规则将允许组成员读取groups
集合(如果其userId是roles
映射中的键)。
function isMemberOfGroup(userId, groupId) {
return userId in get(/databases/$(database)/documents/groups/$(groupId)).data.roles.keys();
}
match /groups/{groupId} {
allow read: if isMemberOfGroup(request.auth.uid, groupId);
}
样品组收集
{
name: "Group1"
roles: {
uid: "member"
}
}
我的单元测试对单个文档执行get()
,该文档成功。
然后它使用get()
查询执行where()
,但失败。
it("[groups] any member of a group can read", async () => {
const admin = adminApp({ uid: "admin" });
const alice = authedApp({ uid: "alice" });
// Groups collection initialisation
await firebase.assertSucceeds(
admin.collection("groups")
.doc("group1")
.set({ name: "Group1", roles: { alice: "member" } })
);
// This succeeds
await firebase.assertSucceeds(
alice.collection("groups")
.doc("group1")
.get()
);
// This fails
await firebase.assertSucceeds(
alice.collection("groups")
.where(new firebase.firestore.FieldPath('roles', 'alice'), '==', "member")
.get()
);
});
它失败并显示错误:
FirebaseError:
Null value error. for 'list' @ L30
其中L30
指向allow read
安全规则
我知道Firestore规则不负责过滤,并且会拒绝任何可能包含规则外文档的请求。 但是据我了解,我的where()应该正确地限制了这一点。
我的where()
查询或规则是否有问题?
答案 0 :(得分:1)
问题仍然是安全规则不是过滤器。由于您的规则取决于特定的文档ID(在您的情况下为groupId
),因此该值永远不能在规则中用作比较的一部分。由于规则不是过滤器,因此该规则必须适用于groupId
的任何可能的值,而不会知道其前进,因为该规则不会get()
并检查每个单独的组文档。
由于这个原因,您现在拥有的安全检查根本无法用于查询。相反,请考虑将每个用户组访问权限的列表存储在自定义声明中或用户可以阅读的单个文档中,以便他们可以迭代该列表,并仅get()
告知被告知他们有权访问的特定组