Buka konsol

Mengkueri Data dengan Aman

Halaman ini menjabarkan konsep dalam Membuat Struktur Aturan Keamanan dan Menulis Condition untuk Aturan Keamanan untuk menjelaskan cara interaksi Aturan Keamanan Cloud Firestore dengan kueri. Di sini Anda dapat menemukan bahasan lebih dalam tentang pengaruh aturan keamanan terhadap kueri yang dapat Anda tulis, dan menjelaskan cara memastikan kueri Anda menggunakan batasan yang sama seperti aturan keamanan. Halaman ini juga menjelaskan cara menulis aturan keamanan untuk mengizinkan atau menolak kueri berdasarkan properti kueri seperti limit dan orderBy.

Kueri dan aturan keamanan

Saat menulis kueri untuk mengambil dokumen, ingat bahwa aturan keamanan bukanlah filter. Kueri bersifat semua atau tidak ada sama sekali. Untuk menghemat waktu dan resource, Cloud Firestore mengevaluasi kueri terhadap kumpulan hasil potensial, bukan nilai kolom aktual untuk semua dokumen Anda. Jika kueri berpotensi untuk menampilkan dokumen, tapi klien tidak memiliki akses baca ke dokumen tersebut, keseluruhan permintaan akan gagal.

Seperti yang ditunjukkan contoh di bawah ini, Anda harus menuliskan kueri agar sesuai dengan batasan aturan keamanan.

Mengamankan dan mengkueri dokumen berdasarkan auth.uid

Contoh berikut menunjukkan cara menulis kueri untuk mengambil dokumen yang dilindungi oleh aturan keamanan. Pertimbangkan database yang berisi kumpulan dokumen story:

/stories/{storyid}

{
  title: "A Great Story",
  content: "Once upon a time...",
  author: "some_auth_id",
  published: false
}

Selain kolom title dan content, setiap dokumen menyimpan kolom author dan published yang digunakan untuk kontrol akses. Contoh ini mengasumsikan bahwa aplikasi tersebut menggunakan Firebase Authentication untuk menetapkan kolom author ke UID pengguna yang membuat dokumen. Firebase Authentication juga mengisi variabel request.auth dalam aturan keamanan.

Aturan keamanan berikut menggunakan variabel request.auth dan resource.data untuk membatasi akses baca dan tulis untuk setiap story pada penulisnya:

service cloud.firestore {
  match /databases/{database}/documents {
    match /stories/{storyid} {
      // Only the authenticated user who authored the document can read or write
      allow read, write: if request.auth.uid == resource.data.author;
    }
  }
}

Misalkan aplikasi Anda menyertakan halaman yang menunjukkan kepada pengguna daftar dokumen story yang ditulisnya. Anda mungkin berharap dapat menggunakan kueri berikut untuk mengisi halaman ini. Namun, kueri ini akan gagal, karena tidak menyertakan batasan yang sama seperti aturan keamanan Anda:

Tidak valid: Batasan kueri tidak cocok dengan batasan aturan keamanan

// This query will fail
db.collection("stories").get()

Kueri gagal meskipun pengguna saat ini adalah penulis dari setiap dokumen story. Perilaku ini muncul karena ketika menerapkan aturan keamanan Anda, Cloud Firestore mengevaluasi kueri berdasarkan kumpulan hasil potensial, bukan berdasarkan properti dokumen sebenarnya di database Anda. Jika kueri berpotensi menyertakan dokumen yang melanggar aturan keamanan Anda, kueri akan gagal.

Sebaliknya, kueri berikut berhasil karena menyertakan batasan di kolom author, yang sama dengan batasan pada aturan keamanan:

Valid: Batasan kueri sesuai dengan batasan aturan keamanan

var user = firebase.auth().currentUser;

db.collection("stories").where("author", "==", user.uid).get()

Mengamankan dan mengkueri dokumen berdasarkan kolom

Untuk menunjukkan lebih lanjut tentang interaksi antara kueri dan aturan, aturan keamanan di bawah ini memperluas akses baca untuk koleksi stories agar pengguna dapat membaca dokumen story tempat kolom published disetel ke true.

service cloud.firestore {
  match /databases/{database}/documents {
    match /stories/{storyid} {
      // Anyone can read a published story; only story authors can read unpublished stories
      allow read: if resource.data.published == true || request.auth.uid == resource.data.author;
      // Only story authors can write
      allow write: if request.auth.uid == resource.data.author;
    }
  }
}

Kueri untuk halaman yang dipublikasikan harus menyertakan batasan yang sama seperti aturan keamanan:

db.collection("stories").where("published", "==", true).get()

Batasan kueri .where("published", "==", true) menjamin bahwa resource.data.published adalah true untuk setiap hasil. Oleh karena itu, kueri ini memenuhi aturan keamanan dan diizinkan untuk membaca data.

Mengevaluasi batasan pada kueri

Aturan keamanan Anda juga dapat menerima atau menolak kueri berdasarkan batasannya. Variabel request.query berisi properti limit, offset, dan orderBy dari sebuah kueri. Misalnya, aturan keamanan Anda dapat menolak kueri apa saja yang tidak membatasi jumlah maksimum dokumen yang diambil pada rentang tertentu:

allow list: if request.query.limit <= 10;

Kumpulan aturan berikut menunjukkan cara menulis aturan keamanan yang mengevaluasi batasan yang digunakan pada kueri. Contoh ini memperluas kumpulan aturan stories sebelumnya dengan perubahan berikut:

  • Kumpulan aturan tersebut memisahkan aturan baca menjadi aturan get dan list.
  • Aturan get membatasi pengambilan dokumen tunggal untuk dokumen publik atau dokumen yang ditulis penyusunnya.
  • Aturan list menerapkan pembatasan yang sama seperti get, tapi untuk kueri. Aturan ini juga memeriksa batas kueri, lalu menolak kueri yang tidak memiliki batas atau dengan batas lebih dari 10.
  • Kumpulan aturan mendefinisikan fungsi authorOrPublished() untuk menghindari duplikasi kode.
service cloud.firestore {

  match /databases/{database}/documents {

    match /stories/{storyid} {

      // Returns `true` if the requested story is 'published'
      // or the user authored the story
      function authorOrPublished() {
        return resource.data.published == true || request.auth.uid == resource.data.author;
      }

      // Deny any query not limited to 10 or fewer documents
      // Anyone can query published stories
      // Authors can query their unpublished stories
      allow list: if request.query.limit <= 10 &&
                     authorOrPublished();

      // Anyone can retrieve a published story
      // Only a story's author can retrieve an unpublished story
      allow get: if authorOrPublished();

      // Only a story's authors can write to a story
      allow write: if request.auth.uid == resource.data.author;
    }

  }
}

Langkah berikutnya