Buka konsol

Menulis condition untuk Aturan Keamanan Cloud Firestore

Panduan ini dikembangkan dari panduan membuat struktur aturan keamanan untuk menunjukkan cara menambahkan condition ke Aturan Keamanan Cloud Firestore. Jika Anda belum menguasai dasar-dasar Aturan Keamanan Cloud Firestore, baca panduan memulai.

Elemen penyusun utama Aturan Keamanan Cloud Firestore adalah condition. Condition adalah operasi boolean yang menentukan apakah operasi tertentu diizinkan atau ditolak. Gunakan aturan keamanan untuk menulis condition yang memeriksa autentikasi pengguna, memvalidasi data masuk, atau mengakses bagian lain dalam database Anda.

Autentikasi

Salah satu pola aturan keamanan yang paling umum adalah mengontrol akses berdasarkan status autentikasi pengguna. Misalnya, aplikasi Anda mungkin hanya ingin mengizinkan pengguna yang telah login untuk menulis data:

service cloud.firestore {
  match /databases/{database}/documents {
    // Allow the user to access documents in the "cities" collection
    // only if they are authenticated.
    match /cities/{city} {
      allow read, write: if request.auth.uid != null;
    }
  }
}

Pola umum lainnya adalah memastikan bahwa pengguna hanya dapat membaca dan menulis data mereka sendiri:

service cloud.firestore {
  match /databases/{database}/documents {
    // Make sure the uid of the requesting user matches name of the user
    // document. The wildcard expression {userId} makes the userId variable
    // available in rules.
    match /users/{userId} {
      allow read, update, delete: if request.auth.uid == userId;
      allow create: if request.auth.uid != null;
    }
  }
}

Jika aplikasi Anda menggunakan Firebase Authentication, variabel request.auth akan berisi informasi autentikasi untuk klien yang meminta data. Untuk mengetahui informasi lebih lanjut tentang request.auth, lihat dokumentasi referensi.

Validasi data

Banyak aplikasi yang menyimpan informasi kontrol akses sebagai kolom pada dokumen di database. Aturan Keamanan Cloud Firestore dapat mengizinkan atau menolak akses secara dinamis berdasarkan data dokumen:

service cloud.firestore {
  match /databases/{database}/documents {
    // Allow the user to read data if the document has the 'visibility'
    // field set to 'public'
    match /cities/{city} {
      allow read: if resource.data.visibility == 'public';
    }
  }
}

Variabel resource mengacu pada dokumen yang diminta, dan resource.data adalah peta dari semua kolom dan nilai yang tersimpan pada dokumen tersebut. Untuk mengetahui informasi lebih lanjut tentang variabel resource, lihat dokumentasi referensi.

Ketika menulis data, Anda mungkin ingin membandingkan data yang masuk dengan data yang ada. Dalam hal ini, jika kumpulan aturan Anda mengizinkan penulisan tertunda, variabel request.resource akan memuat status waktu mendatang dari dokumen tersebut. Untuk operasi update yang hanya mengubah sub-kumpulan kolom dokumen, variabel request.resource akan memuat status dokumen tertunda setelah pengoperasian. Anda dapat memeriksa nilai kolom ini di request.resource untuk mencegah update data yang tidak diinginkan atau tidak konsisten:

service cloud.firestore {
  match /databases/{database}/documents {
    // Make sure all cities have a positive population and
    // the name is not changed
    match /cities/{city} {
      allow update: if request.resource.data.population > 0
                    && request.resource.data.name == resource.data.name;
    }
  }
}

Mengakses dokumen lain

Aturan keamanan Anda dapat memanfaatkan fungsi get() dan exists() untuk mengevaluasi permintaan yang masuk berdasarkan dokumen lain di database. Fungsi get() dan exists() sama-sama memerlukan lokasi dokumen yang ditentukan secara lengkap. Ketika menggunakan variabel untuk membuat lokasi get() dan exists(), Anda harus melepaskan variabel secara eksplisit menggunakan sintaks $(variable).

Pada contoh di bawah, variabel database ditangkap oleh pernyataan kecocokan match /databases/{database}/documents dan digunakan untuk membentuk lokasi:

service cloud.firestore {
  match /databases/{database}/documents {
    match /cities/{city} {
      // Make sure a 'users' document exists for the requesting user before
      // allowing any writes to the 'cities' collection
      allow create: if exists(/databases/$(database)/documents/users/$(request.auth.uid))

      // Allow the user to delete cities if their user document has the
      // 'admin' field set to 'true'
      allow delete: if get(/databases/$(database)/documents/users/$(request.auth.uid)).data.admin == true
    }
  }
}

Untuk penulisan, Anda dapat menggunakan fungsi getAfter() untuk mengakses status dokumen setelah sebuah transaksi atau batch penulisan selesai, namun sebelum transaksi atau batch tersebut dijalankan. Seperti get(), fungsi getAfter() mengambil lokasi dokumen yang ditentukan secara lengkap. Anda dapat menggunakan getAfter() untuk menentukan set penulisan yang harus dilakukan bersama sebagai sebuah transaksi atau batch.

Batas akses panggilan

Ada batasan pada panggilan akses dokumen per evaluasi aturan yang ditetapkan:

  • 10 untuk permintaan dokumen tunggal dan permintaan kueri.
  • 20 untuk pembacaan, transaksi, dan penulisan batch multi-dokumen. Batas 10 sebelumnya juga berlaku untuk setiap operasi.

    Misalnya, bayangkan Anda membuat permintaan penulisan batch dengan 3 operasi penulisan dan aturan keamanan yang menggunakan 2 panggilan akses dokumen untuk memvalidasi setiap penulisan. Dalam hal ini, setiap penulisan menggunakan 2 dari 10 panggilan aksesnya dan permintaan penulisan batch menggunakan 6 dari 20 panggilan aksesnya.

Melebihi salah satu batas akan menyebabkan error izin ditolak. Beberapa panggilan akses dokumen dapat di-cache, dan panggilan yang di-cache tidak diperhitungkan batasnya.

Untuk mengetahui penjelasan lengkap mengenai bagaimana pengaruh batas ini terhadap transaksi dan penulisan batch, lihat panduan untuk mengamankan operasi menyeluruh.

Panggilan akses dan harga

Penggunaan fungsi ini akan memicu operasi baca di database, yang berarti Anda akan ditagih untuk pembacaan dokumen meskipun aturan Anda menolak permintaan tersebut. Baca Harga Cloud Firestore untuk mengetahui informasi tagihan secara lebih spesifik.

Fungsi kustom

Saat aturan keamanan Anda menjadi semakin kompleks, Anda mungkin ingin mengemas kumpulan condition ke dalam fungsi yang dapat digunakan kembali di semua kumpulan aturan. Aturan keamanan mendukung fungsi kustom. Sintaks untuk fungsi kustom mirip dengan JavaScript, namun fungsi aturan keamanan ditulis dalam bahasa khusus domain yang memiliki beberapa batasan penting:

  • Fungsi hanya dapat berisi satu pernyataan return. Fungsi tidak boleh berisi logika lain apa pun. Misalnya, fungsi tidak dapat membuat variabel perantara, menjalankan loop, atau memanggil layanan eksternal.
  • Fungsi dapat secara otomatis mengakses fungsi dan variabel dari cakupan tempat ditetapkannya. Misalnya, fungsi yang ditetapkan ke dalam cakupan service cloud.firestore memiliki akses ke variabel resource dan memiliki fungsi bawaan seperti get() dan exists().
  • Fungsi dapat memanggil fungsi lain namun mungkin tidak secara berulang. Total tumpukan panggilan dibatasi sampai 10.

Fungsi ditetapkan dengan kata kunci function dan menerima 0 atau lebih argumen. Misalnya, Anda mungkin ingin menggabungkan dua jenis kondisi yang digunakan dalam contoh di atas menjadi sebuah fungsi:

service cloud.firestore {
  match /databases/{database}/documents {
    // True if the user is signed in or the requested data is 'public'
    function signedInOrPublic() {
      return request.auth.uid != null || resource.data.visibility == 'public';
    }

    match /cities/{city} {
      allow read, write: if signedInOrPublic();
    }

    match /users/{user} {
      allow read, write: if signedInOrPublic();
    }
  }
}

Dengan menggunakan fungsi, aturan keamanan akan lebih mudah dipertahankan seiring semakin kompleksnya aturan.

Aturan bukanlah filter

Setelah Anda mengamankan data dan mulai menulis kueri, perlu diingat bahwa aturan keamanan bukanlah filter. Anda tidak dapat menulis kueri untuk semua dokumen dalam koleksi dan mengharapkan Cloud Firestore hanya mengembalikan dokumen yang diizinkan oleh klien saat ini.

Misalnya, lakukan tindakan berikut:

service cloud.firestore {
  match /databases/{database}/documents {
    // Allow the user to read data if the document has the 'visibility'
    // field set to 'public'
    match /cities/{city} {
      allow read: if resource.data.visibility == 'public';
    }
  }
}

Ditolak: Aturan ini menolak kueri berikut karena kumpulan hasil dapat menyertakan dokumen yang visibility tidak public:

Web
db.collection("cities").get()
    .then(function(querySnapshot) {
        querySnapshot.forEach(function(doc) {
            console.log(doc.id, " => ", doc.data());
    });
});

Diizinkan: Aturan ini mengizinkan kueri berikut karena klausa di where("visibility", "==", "public") menjamin bahwa kumpulan hasil tersebut memenuhi ketentuan aturan:

Web
db.collection("cities").where("visibility", "==", "public").get()
    .then(function(querySnapshot) {
        querySnapshot.forEach(function(doc) {
            console.log(doc.id, " => ", doc.data());
        });
    });

Aturan keamanan Cloud Firestore mengevaluasi setiap kueri terhadap hasil potensial dan gagal permintaan jika dapat mengembalikan dokumen yang klien tidak memiliki izin untuk membaca. Kueri harus mengikuti batasan yang ditetapkan oleh aturan keamanan Anda. Untuk mengetahui informasi aturan keamanan dan kueri lebih lanjut, lihat data kueri yang aman.

Langkah berikutnya