Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/391.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 限制阅读聊天信息的Firestore安全规则_Javascript_Google Cloud Firestore_Firebase Security - Fatal编程技术网

Javascript 限制阅读聊天信息的Firestore安全规则

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

在我使用Firestore的1-1聊天应用程序中,两名参与者将在
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条件。有几种解决方案:

  • 将每条消息的参与者UID存储在数组字段中(例如
    参与者
    ),然后使用
    数组包含
    查询:

    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条件。有几种解决方案:

  • 将每条消息的参与者UID存储在数组字段中(例如
    参与者
    ),然后使用
    数组包含
    查询:

    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)<