web-dev-qa-db-ja.com

Firebase Firestore:カスタム管理者アクセス

Firebase Firestoreでは、(カスタム割り当てされた)管理者のみにリソースの書き込み/更新/削除を許可しようとしています。そのために、次のセキュリティルールがあります。

service cloud.firestore {
  match /databases/{database}/documents {
    match /resources {
      allow read;
      allow write, update, delete: if get(/users/$(request.auth.uid).isAdmin);
    }
    match /resources/{resource} {
      allow read;
      allow write, update, delete: if get(/users/$(request.auth.uid).isAdmin);
    }
  }
}

usersコレクションで管理者としてマークされているユーザーでサインインしています:

users collection has a single admin

NfwIQAjfNdS85yDvd5yPVDyMTUj2は、認証ペインから取得したUIDです。

The user exists

ただし、何らかの理由で(PDATE:理由が特定されました。回答を参照)、書き込み時にPERMISSION_DENIEDエラーが発生します。 resourcesコレクションは、管理者ユーザーでサインインしていることを絶対に確認した後です。

おそらく、Firestoreからリクエストログを表示することは可能ですか?それから私は何を見ることができましたrequest.auth.uidそれを私のコレクションやルールと一致させるように見えます。

10
sindrenm

質問を書いている間、私はそれを機能させました!私は2つの間違いを犯しましたが、ドキュメントを正しく読めば、どちらも回避できたはずです。

最初にサービス定義関数getへのすべての呼び出しでは、パスの前に/ databases/$(database)/ documents /。そのため、このルールは次のとおりです。

allow write: if get(/users/$(request.auth.uid)).isAdmin;

これになります:

allow write: if get(/databases/$(database)/documents/users/$(request.auth.uid)).isAdmin;

長いですが、そうです。 Firestoreがそれ自体でそれを実行できない理由はわかりませんが、同じパスプレフィックスがgetへのすべての呼び出しで同じままであるため、おそらくこれは将来の機能のためです。クロスデータベースクエリなど、まだ準備ができていません。

Secondget関数は resource を返します。これは、.dataを呼び出す必要があります。含まれている実際のデータを取得します。したがって、これを行う代わりに:

get(/path/to/user/).isAdmin

これを行う必要があります:

get(/path/to/user/).data.isAdmin

今、私はそのロジックを ユーザー定義関数 に抽出できたらいいのにと思います:

function isAdmin() {
  return get(/databases/$(database)/documents/users/$(request.auth.uid)).data.isAdmin;
}

しかし、そうすると再びPERMISSION_DENIEDになり、関数で実際に何が起こっているのかを知らずに、これを理解するためにもっと時間を費やすかどうかはわかりません。

UPDATE:@ Hareesh 指摘 関数はマッチャーのスコープ内で定義する必要があるため、関数を配置することができます次のようなデフォルトのトップレベルマッチャーで:

service cloud.firestore {
  match /databases/{database}/documents {
    function isAdmin() {
      return get(/databases/$(database)/documents/users/$(request.auth.uid)).data.isAdmin == true;
    }

    // ...
  }
}
14
sindrenm

私が気づいたいくつかのポイント

match /resourcesはコレクションを指しており、そのルールはそのドキュメントに影響を与えません。ここで私は doc から引用しています

コレクションのルールは、そのコレクション内のドキュメントには適用されません。ドキュメントレベルではなくコレクションレベルで記述されたセキュリティルールがあるのは珍しいことです(そしておそらくエラーです)。

したがって、コレクションのルールを作成する必要はありません

次に、ルールでallow write, update, delete:あなたはどちらかを言うことができますallow write:または具体的にはallow create, update, delete:3つのオプションのいずれかまたはそれらを組み合わせます。

これを試して

service cloud.firestore {
    match /databases/{database}/documents {
      match /resources/{resource} {

        function isAdmin() {
            return get(/databases/$(database)/documents/users/$(request.auth.uid)).isAdmin ||
            get(/databases/$(database)/documents/users/$(request.auth.uid)).data.isAdmin;
        }

        allow read;
        allow create, update, delete: if isAdmin();
    }
  }
}
3
Hareesh