繁体   English   中英

Firestore 实时数据库身份验证规则

[英]Firestore Realtime Database authentication rules

给定以下数据结构:

Firestore 数据

无论如何,是否可以根据条目的复合键中 auth.uid 的存在来验证读取请求? 例如“5f6d9d83258b65b5f272aa9f|5f79b99dc6a7c11b9c0eab78”中的“5f79b99dc6a7c11b9c0eab78”?

我试过这个 - 但我假设 contains 与条目中的字段相关,而不是密钥本身。

   {
      "rules": {
          "messages": {
            "$message": {
              ".read":  "$message.contains(auth.uid)"          
            }
          }
        }    
    }

编辑:

这是我对用户进行身份验证、预取现有消息(我将在此处添加一些进一步的逻辑以一次仅提取 X 条消息)、发送和检索新消息的代码。

import * as firebase from "firebase/app";
import "firebase/auth";    
import "firebase/database";

export const initClient = async (token) => {
  if (!firebase.apps.length) {
    var firebaseConfig = {
      apiKey: "[API]",
      authDomain: "[DOMAIN]",
      databaseURL: "[URL]",
      projectId: "[ID]",
      storageBucket: "[STORAGE]",
      messagingSenderId: "[SENDERID]",
      appId: "[APP_ID]",
      measurementId: "[MEAS_ID]"
    };

    firebase.initializeApp(firebaseConfig);

    await firebase.auth().signInWithCustomToken(token).catch(function (error) {
      var errorCode = error.code;
      var errorMessage = error.message;
      //todo
    });

    return { authenticated: true }
  }   

}

export const writeMessage = (fromId, chatId, message) => {
  var newMessageKey = firebase.database().ref().child('messages/' + chatId).push().key;
  
  firebase.database().ref('messages/' + chatId + '/' + newMessageKey).set({
    senderId: fromId,
    message: encodeURIComponent(message)
  });
}

//get all messages once when a particular chat window is open - works fine without auth rules in place
export const getMessages = async (chatId) => {  
  //chatId = '5f6d9d83258b65b5f272aa9f|5f79b99dc6a7c11b9c0eab78
  var ref = firebase.database().ref('messages/' + chatId);
  const snapshot = await ref.once('value')
  const messages = snapshot.val();
  const messagesArray = Object.keys(messages).map(key => ({ ...messages[key], message: decodeURIComponent(messages[key].message), messageId: key }))
  
  return { chatId, messages: messagesArray };
}


let bound = false;
//set listeners to get new messages and pass the messages back into the application
export const setMessageListeners = async (chatId, onNewMessage) => {
  if(bound) return;
  bound = true;  
  var ref = firebase.database().ref('messages/' + chatId);
  ref.endAt().limitToLast(1).on('child_added', function (data) {
      onNewMessage(chatId, data.key, decodeURIComponent(data.val().message), data.val().senderId);      
  });
}

也许我需要为每个请求对自定义令牌做些什么?

我可能应该注意到,我也无法获得在规则编辑器游乐场内玩球的规则。 毫无疑问,它与我用来测试的有效载荷有关。

除此之外,我有一些服务器端逻辑来跟踪每个对话,这些数据实际上存储在 RTDB 之外——上面纯粹是一个消息存储。

编辑:排序!

{
  "rules": {
      "messages": {
        "$conversation": {
          ".read":  "$conversation.contains(auth.uid)",
            "$message": {
                ".write": "newData.child('senderId').val() === auth.uid && !data.exists() || data.child('senderId').val() === auth.uid && data.exists()"
            }
        }
        }
  }    
}

看来我的问题实际上根本不是问题。 只是我错误地使用了 playground,并在与规则集中的动态键匹配的路径段中添加了花括号(不知道为什么,但我确定我在某处看到过)。 上面的结构是我现在确定的。 参与对话的任何人都可以阅读消息(直到我添加已删除的属性,而不是删除消息我只是隐藏它)。 如果新项目不存在,您可以编写它们,或者更新属于您的现有消息。

谢谢你的帮助!

我只是尝试重现这个问题,但它似乎对我来说工作正常。 我将在下面分享我的代码、数据和规则,希望它们能帮助您找到问题/差异。

我的JSON:

{
  "anotheruser-m4yXaC9wmCdJXOiL2LDPEJDPoHw1" : "value2",
  "m4yXaC9wmCdJXOiL2LDPEJDPoHw1-anotheruser" : "value1"
}

我的代码:

firebase.auth().signInAnonymously();

firebase.auth().onAuthStateChanged(function(user) {
  if (user) {
    console.log("uid: "+user.uid);
    var ref = firebase.database().ref("64258893");
    ref.child("m4yXaC9wmCdJXOiL2LDPEJDPoHw1-anotheruser").once("value")
    .then(function(snapshot) {
      console.log(snapshot.key+": "+snapshot.val());
    }).catch(function(error) {
      console.error(error);
    });
  }
});

我对节点64258893的安全规则:

{
  "rules": {
    "64258893": { 
      "$message": {
        ".read": "$message.contains(auth.uid)"
      }
    },
    ...

此代码记录:

“uid:m4yXaC9wmCdJXOiL2LDPEJDPoHw1”

“m4yXaC9wmCdJXOiL2LDPEJDPoHw1-另一个用户:value1”

这正是我所期望的,因为您可以看到 UID 嵌入在密钥中。 如果我将读取更改为不包含 UID 的其他路径(如ref.child("yes-anotheruser") ,则读取将被拒绝。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM