Javascript 限制阅读聊天信息的Firestore安全规则
在我使用Firestore的1-1聊天应用程序中,两名参与者将在Javascript 限制阅读聊天信息的Firestore安全规则,javascript,google-cloud-firestore,firebase-security,Javascript,Google Cloud Firestore,Firebase Security,在我使用Firestore的1-1聊天应用程序中,两名参与者将在msgs子集合中读/写文档,其中每个文档都是一条消息。 但是由于安全规则,它在拒绝许可的情况下失败了 数据库结构: chatRooms/ ${roomId}/ msgs/ ${msgId} 我想添加安全规则,以便只有相关的2名参与者能够读取/写入其roomId文档的msgs子集合 我编写了以下安全规则。 它允许参与者在msgs子集合中创建新文档(即发送消息)。 但用户无法阅读此msg
msgs
子集合中读/写文档,其中每个文档都是一条消息。但是由于安全规则,它在拒绝许可的情况下失败了 数据库结构:
chatRooms/
${roomId}/
msgs/
${msgId}
我想添加安全规则,以便只有相关的2名参与者能够读取/写入其roomId
文档的msgs
子集合
我编写了以下安全规则。它允许参与者在
msgs
子集合中创建新文档(即发送消息)。但用户无法阅读此
msgs
子集合
match /chatRooms/{roomId} {
allow read: if request.auth.uid == resource.data.userA.id ||
request.auth.uid == resource.data.userB.id;
allow create: if request.auth.uid == request.resource.data.userA.id ||
request.auth.uid == request.resource.data.userB.id;
match /msgs/{msgId} {
allow read: if request.auth.uid == resource.data.sender._id ||
request.auth.uid == resource.data.partner._id;
allow create: if request.auth.uid == request.resource.data.sender._id ||
request.auth.uid == request.resource.data.partner._id;
}
}
read的代码是:
const roomId = `${userAId}_${userBId}`;
const query = db.collection('chatRooms').doc(roomId).collection('msgs')
.orderBy('createdAt', 'desc')
.startAfter(lastVisible)
.limit(10)
query.get()
如果我像下面这样更改读取规则,则读写操作完全正常。所以我们可以指出,问题只存在于
msgs
子集合的读取规则中。(不在其父集合/单据规则中)
更新: 弗兰克提出了3种解决方案,我尝试了其中的两种(1和3),但都不适合我 对于解决方案1,我添加了一个包含参与者UID的
ids
数组。写入消息(添加新文档)使用相同的安全规则 read op如下所示: 这是安全规则:
更新2 正如弗兰克在回答中评论的那样,它在修正了安全规则后起了作用。(由于这一评论远远低于下文,我也在此处添加)
更新3 解决方案1需要生成一个索引(因为我也使用了
orderBy
),这需要额外的成本。所以我也尝试了Frank的解决方案3,但它返回了“权限拒绝”错误。可能读取查询是错误的,它需要一些过滤器,但我无法在从
msgs
集合读取时,根据规则要求对$roomId
文档数据(userA.id
/userB.id
)添加过滤器
match /chatRooms/{roomId} {
allow read: if request.auth.uid == resource.data.userA.id ||
request.auth.uid == resource.data.userB.id;
allow create: if request.auth.uid == request.resource.data.userA.id ||
request.auth.uid == request.resource.data.userB.id;
match /msgs/{msgId} {
allow read: if request.auth.uid == resource.data.sender._id ||
request.auth.uid == resource.data.partner._id;
allow create: if request.auth.uid == request.resource.data.sender._id ||
request.auth.uid == request.resource.data.partner._id;
}
}
规则:
match /chatRooms/{roomId=**} {
allow read: if request.auth.uid == resource.data.userA.id ||
request.auth.uid == resource.data.userB.id;
allow create: if request.auth.uid == request.resource.data.userA.id ||
request.auth.uid == request.resource.data.userB.id;
allow update: if request.auth.uid == resource.data.userA.id ||
request.auth.uid == resource.data.userB.id;
}
读取查询:
const query = dbFirestore.collection('chatRooms').doc(roomId).collection('msgs')
.orderBy('createdAt', 'desc')
.limit(10)
query.onSnapshot( ... )
安全规则不过滤数据。相反,它们只是检查是否允许读取操作 因此,如果您想允许用户只读取他们所属的消息,则必须执行一个选择这些消息的查询 例如:您可以使用以下选项选择用户作为发件人的所有邮件:
db.collection('chatRooms').doc(roomId).collection('msgs')
where('sender._id', '==', firebase.auth().currentUser.uid)
现在,安全规则将检查是否允许此查询,并返回相应的消息
然后,问题就变成了无法对
发送方.\u id
和合作伙伴.\u id
字段执行OR条件。有几种解决方案:
参与者
),然后使用数组包含
查询:
db.collection('chatRooms').doc(roomId).collection('msgs')
where('participants', 'array-contains', firebase.auth().currentUser.uid)
然后在规则中用如下方式确保:
request.auth.uid in resource.data.participants
/chattrooms/$roomId
级别上,通过msgs
子集合上的查找,为房间的安全性建模。这需要两个额外的get,但除此之外要简单得多
match /msgs/{msgId} {
allow read: if request.auth != null &&
(get(/databases/$(database)/documents/chatRooms/$(roomId)).data.userA.id == request.auth.uid
|| get(/databases/$(database)/documents/chatRooms/$(roomId)).data.userB.id == request.auth.uid);
/msgs
的访问权:
match /chatRooms/{roomId=**} {
allow read: if request.auth.uid == resource.data.userA.id ||
request.auth.uid == resource.data.userB.id;
安全规则不过滤数据。相反,它们只是检查是否允许读取操作 因此,如果您想允许用户只读取他们所属的消息,则必须执行一个选择这些消息的查询 例如:您可以使用以下选项选择用户作为发件人的所有邮件:
db.collection('chatRooms').doc(roomId).collection('msgs')
where('sender._id', '==', firebase.auth().currentUser.uid)
现在,安全规则将检查是否允许此查询,并返回相应的消息
然后,问题就变成了无法对
发送方.\u id
和合作伙伴.\u id
字段执行OR条件。有几种解决方案:
参与者
),然后使用数组包含
查询:
db.collection('chatRooms').doc(roomId).collection('msgs')
where('participants', 'array-contains', firebase.auth().currentUser.uid)
然后在规则中用如下方式确保:
request.auth.uid in resource.data.participants
/chattrooms/$roomId
级别上,通过msgs
子集合上的查找,为房间的安全性建模。这需要两个额外的get,但除此之外要简单得多
match /msgs/{msgId} {
allow read: if request.auth != null &&
(get(/databases/$(database)/documents/chatRooms/$(roomId)).data.userA.id == request.auth.uid
|| get(/databases/$(database)/documents/chatRooms/$(roomId)).data.userB.id == request.auth.uid);
/msgs
的访问权:
match /chatRooms/{roomId=**} {
allow read: if request.auth.uid == resource.data.userA.id ||
request.auth.uid == resource.data.userB.id;
谢谢你,弗兰克,你的解释很有用。我想我将采用第一种方法。对不起,我想先测试解决方案,然后标记它已解决。第三种解决方案对我不起作用,所以我尝试了第一种。但这也不起作用:(--read op:
query=db.collection('chattrooms').doc(roomId).collection('msgs').where('ids','array-contains',firebase.auth().currentUser.uid)
--规则:match/msgs/{msgId}{allow read:if request.auth.uid==resource.data.ids[0]| | request.auth.uid==resource.data.ids[1];}
-----虽然write使用相同的规则工作,并且我确认生成的文档中包含参与者ID的ids
数组,请使用新的查询、规则和文档的屏幕截图更新您的问题。在注释中读取这些内容太难了。这些数组比较不起作用,因为数组包含,而规则执行两次=
检查。我希望在resource.data.ids
.Hmmm中出现request.auth.uid…我确实不确定这是否有效。主要是:规则如何验证从传入的信息中读取的操作。因此方法3可能不可能。谢谢@Frank,你的解释非常有用。我认为我将使用第一种方法。很抱歉,我想先测试解决方案,然后将其标记为已解决。第三种解决方案对我不起作用,所以我尝试了第一种解决方案。但也不起作用:(--read op:query=db.collection('chattooms').doc(roomId).collection('msgs')。where('id','array-contains',firebase.auth().currentUser.uid)<