Firebase Realtime数据库侦听器的行为根据安全规则而有所不同 [英] Firebase Realtime database listeners behave differently depending on the security rules

查看:83
本文介绍了Firebase Realtime数据库侦听器的行为根据安全规则而有所不同的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我当前从Firebase Realtime数据库中收到意外行为.为了重现它,我仅在将Vanilla JS与Firebase JavaScript SDK(7.19.1)配合使用时,才使用下面的代码.

代码:
两个版本保持相同.
仅安全规则将直接在Firebase中更改.

 const CONFIG = { ... };  // TODO insert your config
const AUTH_TOKEN = "eyJ0..."  // TODO insert your auth token (JWT)

firebase.initializeApp(CONFIG);

firebase
  .auth()
  .signInWithCustomToken(AUTH_TOKEN)
  .then(() => {
    console.log("authentication successful");
    performFirebaseOperations();
  })
  .catch((error) => {
    console.log("authentication failed", error);
  });

const performFirebaseOperations = () => {
  const database = firebase.database();
  const allUsersRef = database.ref("users");
  const myUserRef = database.ref("users/1");

  allUsersRef.on("child_added", (data) => {
    console.log("child_added", data.val());
  });

  allUsersRef.on("child_removed", (data) => {
    console.log("child_removed", data.val());
  });

  myUserRef
    .update({
      name: "John",
    })
    .then(() => {
      console.log("update success");
    })
    .catch((error) => {
      console.log("update error", error);
    });
};

 


版本1

安全规则:

 {
  "rules": {
    ".write": false,
    "users": {
      ".read": "auth !== null",
      "$userId": {
        ".write": false,
      }
    }
  }
}
 

控制台输出:


版本2

安全规则:

 {
  "rules": {
    ".write": false,
    ".read": false
  }
}
 

控制台输出:


在两个版本中,都不会将任何内容写入Firebase数据库,因为安全规则不允许这样做.

解决方案

我想我明白了,但这是另一种情况.

通过使客户端在执行任何其他操作之前脱机,我能够使用允许写入的规则获得相同的结果.

firebase.database().goOffline();

到那时,第一组规则的行为与第二组规则的行为相同.

我的测试平台,尽管您无法更改我的规则: https://jsbin.com/guzowak/edit?js,控制台

给出这个...


这可以确保Firebase客户端永远不会向您显示部分快照.

在您的第一种情况下,流程如下:

  1. 您的客户端侦听/users(对于child_addedchild_removed,但是它们中的任何一个都足以完成此步骤),因此它将获取所有用户的数据快照.

  2. >
  3. 然后您执行对/users/1的写操作,这是客户端已经知道的节点的修改,因此它可以触发该更改的本地事件.

在第二种情况下,客户端在步骤1中永远不会获取/users的数据,因此它无法在步骤2中触发事件.

I'm currently getting an unexpected behaviour from the Firebase Realtime database. To reproduce it I've used exactly the code below only using the Firebase JavaScript SDK (7.19.1) with Vanilla JS.

Code:
Stays the same for both versions.
Only the security rules will be changed directly in Firebase.

const CONFIG = { ... };  // TODO insert your config
const AUTH_TOKEN = "eyJ0..."  // TODO insert your auth token (JWT)

firebase.initializeApp(CONFIG);

firebase
  .auth()
  .signInWithCustomToken(AUTH_TOKEN)
  .then(() => {
    console.log("authentication successful");
    performFirebaseOperations();
  })
  .catch((error) => {
    console.log("authentication failed", error);
  });

const performFirebaseOperations = () => {
  const database = firebase.database();
  const allUsersRef = database.ref("users");
  const myUserRef = database.ref("users/1");

  allUsersRef.on("child_added", (data) => {
    console.log("child_added", data.val());
  });

  allUsersRef.on("child_removed", (data) => {
    console.log("child_removed", data.val());
  });

  myUserRef
    .update({
      name: "John",
    })
    .then(() => {
      console.log("update success");
    })
    .catch((error) => {
      console.log("update error", error);
    });
};


Version 1

Security rules:

{
  "rules": {
    ".write": false,
    "users": {
      ".read": "auth !== null",
      "$userId": {
        ".write": false,
      }
    }
  }
}

Console output:


Version 2

Security rules:

{
  "rules": {
    ".write": false,
    ".read": false
  }
}

Console output:


In both version nothing is ever written to the Firebase database because the security rules will not allow this.

This article explains that the Firebase Realtime database operations are optimistic which explains why child_added is displayed in the console even though it's never written to the database. From my understanding Version 1 is the expected behaviour. But why doesn't Version 2 show the same behaviour even though I've only changed the security rules? I thought the update is optimistic without going to the server first, so I expected a child_added event.

解决方案

I think I figured it out, but it's another edge case.

I was able to get the same result with the rules that allow writing, by making the client go offline before any other operation.

firebase.database().goOffline();

At that point the behavior with your first set of rules is the same as with the second set of rules.

My testbed, although you won't be able to change my rules: https://jsbin.com/guzowak/edit?js,console

Given this...


It comes down to a guarantee that the Firebase client makes to never show you a partial snapshot.

In your first case the flow is as follows:

  1. Your client listens to /users (for both child_added or child_removed, but either of them would be enough for this step), so it gets a snapshot of the data for all users.

  2. You then perform a write to /users/1, which is a modification of a node the client already knows, so it can fire a local event for that change.

In your second case, the client never gets the data for /users in step 1, so it can't fire the event in step 2.

这篇关于Firebase Realtime数据库侦听器的行为根据安全规则而有所不同的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆