Firebase Realtime データベース リスナーはセキュリティ ルールに応じて動作が異なります。

okwaves2024-01-25  8

現在、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 Realtime データベースの操作が楽観的であることを説明し、データベースに書き込まれていないにもかかわらず、child_added がコンソールに表示される理由を説明します。私からバージョン 1 が予期される動作であることを理解してください。しかし、セキュリティ ルールを変更しただけであるにもかかわらず、バージョン 2 が同じ動作を示さないのはなぜでしょうか?最初にサーバーにアクセスせずに更新が楽観的に行われると考えたので、child_added イベントが発生することを期待していました。



------------------------

理解できたと思いますが、これはまた特殊なケースです。

他の操作の前にクライアントをオフラインにすることで、書き込みを許可するルールでも同じ結果を得ることができました。

firebase.database().goOffline();

この時点で、最初のルール セットの動作は 2 番目のルール セットの動作と同じになります。

私のテストベッド、ただしあなたにはできません私のルールを変更します: https://jsbin.com/guzowak/edit?js,console

これを踏まえると...

これは、Firebase クライアントが部分的なスナップショットを決して表示しないことを保証することになります。

最初のケースのフローは次のとおりです。

クライアントは /users (child_added と child_removed の両方についてですが、このステップではどちらでも十分です) をリッスンするので、すべてのユーザーのデータのスナップショットを取得します。

次に、/users/1 への書き込みを実行します。これは、クライアントがすでに認識しているノードの変更であるため、その変更に対してローカル イベントを起動できます。

2 番目のケースでは、クライアントはステップ 1 で /users のデータを取得しないため、ステップ 2 でイベントを起動できません。

3

それは興味深いですね。 goOffline 部分のコメントを解除すると、コンソール出力が表示されません。私のバージョンでも試してみましたが、コンソールには「認証成功」のみが出力されました。他の操作はありません。しかし、それがあなたの言いたいことだと思いますか?この操作では何も行われないこと。

– ネポ ズナット

2020 年 9 月 4 日 4:10

オフライン バージョン I で更新操作を設定操作に変更すると、同じ出力が得られます (child_added イベントのみ)。 Firebase にはクライアント側にデータベースのローカル バージョンがあり、このローカル バージョンでは「users」のパスが 1 つあるため、これで理解できたと思います。存在しないため、私が正しく理解していれば、ここで何かを更新することはできません。

– ネポ ズナット

2020 年 9 月 4 日 4:13

1

ええ、この最後の文がまさにその要点です。そして、実際に問題を解決するので、 set() でそれが修正されることに気づかなかったのは残念です。 set() から、クライアントはこれが現在であることを保証できます。ノードの完全な値。このような小さな API の場合、Realtime Database には多くの特殊な動作があります。 :)

– フランク・ヴァン・プフェレン

2020 年 9 月 4 日 14:41

総合生活情報サイト - OKWAVES
総合生活情報サイト - OKWAVES
生活総合情報サイトokwaves(オールアバウト)。その道のプロ(専門家)が、日常生活をより豊かに快適にするノウハウから業界の最新動向、読み物コラムまで、多彩なコンテンツを発信。