Catch up on everthing we announced at this year's Firebase Summit. Learn more

Pelajari sintaks inti bahasa Aturan Database Realtime

Aturan Keamanan Firebase Realtime Database memungkinkan Anda mengontrol akses ke data yang disimpan dalam database Anda. Sintaks aturan yang fleksibel memungkinkan Anda membuat aturan yang cocok dengan apa pun, mulai dari semua penulisan ke database hingga operasi pada masing-masing node.

Realtime database Aturan Keamanan adalah konfigurasi deklaratif untuk database Anda. Ini berarti bahwa aturan didefinisikan secara terpisah dari logika produk. Ini memiliki sejumlah keuntungan: klien tidak bertanggung jawab untuk menegakkan keamanan, implementasi buggy tidak akan membahayakan data Anda, dan mungkin yang paling penting, tidak perlu wasit perantara, seperti server, untuk melindungi data dari dunia.

Topik ini menjelaskan sintaks dasar dan struktur Aturan Keamanan Realtime Database yang digunakan untuk membuat kumpulan aturan lengkap.

Menyusun Aturan Keamanan Anda

Aturan Keamanan Database Realtime terdiri dari ekspresi seperti JavaScript yang terdapat dalam dokumen JSON. Struktur aturan Anda harus mengikuti struktur data yang telah Anda simpan di database Anda.

Aturan dasar mengidentifikasi satu set node harus diamankan, metode akses (misalnya, membaca, menulis) yang terlibat, dan kondisi di mana akses baik diperbolehkan atau ditolak. Dalam contoh berikut, kondisi kita akan sederhana true dan false pernyataan, tetapi dalam topik berikutnya kita akan membahas cara-cara dinamis yang lebih untuk mengekspresikan kondisi.

Jadi, misalnya, jika kita berusaha untuk mengamankan child_node bawah parent_node , sintaks umum untuk mengikuti adalah:

{
  "rules": {
    "parent_node": {
      "child_node": {
        ".read": <condition>,
        ".write": <condition>,
        ".validate": <condition>,
      }
    }
  }
}

Mari kita terapkan pola ini. Misalnya, katakanlah Anda melacak daftar pesan dan memiliki data yang terlihat seperti ini:

{
  "messages": {
    "message0": {
      "content": "Hello",
      "timestamp": 1405704370369
    },
    "message1": {
      "content": "Goodbye",
      "timestamp": 1405704395231
    },
    ...
  }
}

Aturan Anda harus terstruktur dengan cara yang sama. Berikut adalah seperangkat aturan untuk keamanan hanya-baca yang mungkin masuk akal untuk struktur data ini. Contoh ini mengilustrasikan bagaimana kita menentukan node database yang aturannya berlaku dan kondisi untuk mengevaluasi aturan di node tersebut.

{
  "rules": {
    // For requests to access the 'messages' node...
    "messages": {
      // ...and the individual wildcarded 'message' nodes beneath
      // (we'll cover wildcarding variables more a bit later)....
      "$message": {

        // For each message, allow a read operation if <condition>. In this
        // case, we specify our condition as "true", so read access is always granted.
        ".read": "true",

        // For read-only behavior, we specify that for write operations, our
        // condition is false.
        ".write": "false"
      }
    }
  }
}

Operasi Aturan Dasar

Ada tiga jenis aturan untuk menegakkan keamanan berdasarkan jenis operasi yang dilakukan pada data: .write , .read , dan .validate . Berikut adalah ringkasan singkat dari tujuan mereka:

Jenis Aturan
.Baca Menjelaskan jika dan kapan data diizinkan untuk dibaca oleh pengguna.
.menulis Menjelaskan jika dan kapan data diizinkan untuk ditulis.
.mengesahkan Menentukan seperti apa tampilan nilai yang diformat dengan benar, apakah memiliki atribut turunan, dan tipe data.

Variabel Tangkap Wildcard

Semua pernyataan aturan menunjuk ke node. Sebuah pernyataan dapat menunjuk ke node tertentu atau menggunakan $ variabel capture wildcard ke titik ke set node pada tingkat hirarki. Gunakan variabel tangkap ini untuk menyimpan nilai kunci simpul untuk digunakan di dalam pernyataan aturan berikutnya. Teknik ini memungkinkan Anda menulis kondisi Aturan yang lebih kompleks, sesuatu yang kita akan membahas secara lebih rinci dalam topik berikutnya.

{
  "rules": {
    "rooms": {
      // this rule applies to any child of /rooms/, the key for each room id
      // is stored inside $room_id variable for reference
      "$room_id": {
        "topic": {
          // the room's topic can be changed if the room id has "public" in it
          ".write": "$room_id.contains('public')"
        }
      }
    }
  }
}

Dinamika $ variabel juga dapat digunakan secara paralel dengan nama path konstan. Dalam contoh ini, kita menggunakan $other variabel untuk menyatakan .validate aturan yang memastikan bahwa widget tidak memiliki anak lain selain title dan color . Setiap penulisan yang akan menghasilkan anak-anak tambahan yang dibuat akan gagal.

{
  "rules": {
    "widget": {
      // a widget can have a title or color attribute
      "title": { ".validate": true },
      "color": { ".validate": true },

      // but no other child paths are allowed
      // in this case, $other means any key excluding "title" and "color"
      "$other": { ".validate": false }
    }
  }
}

Baca dan Tulis Aturan Cascade

.read dan .write aturan bekerja dari atas ke bawah, dengan aturan dangkal override aturan yang lebih dalam. Jika hibah aturan membaca atau menulis perizinan di jalan tertentu, maka itu juga memberikan akses ke semua node anak di bawah itu. Perhatikan struktur berikut:

{
  "rules": {
     "foo": {
        // allows read to /foo/*
        ".read": "data.child('baz').val() === true",
        "bar": {
          /* ignored, since read was allowed already */
          ".read": false
        }
     }
  }
}

Struktur keamanan ini memungkinkan /bar/ untuk dibaca dari setiap kali /foo/ mengandung anak baz dengan nilai true . The ".read": false aturan di bawah /foo/bar/ tidak berpengaruh di sini, karena akses tidak dapat dicabut oleh jalan anak.

Meskipun tampaknya tidak langsung intuitif, ini adalah bagian yang kuat dari bahasa aturan dan memungkinkan hak akses yang sangat kompleks untuk diimplementasikan dengan sedikit usaha. Ini akan diilustrasikan ketika kita masuk ke keamanan berbasis pengguna nanti dalam panduan ini.

Perhatikan bahwa .validate aturan tidak kaskade. Semua aturan validasi harus dipenuhi di semua tingkat hierarki agar penulisan diizinkan.

Aturan Bukan Filter

Aturan diterapkan secara atomik. Itu berarti bahwa operasi baca atau tulis segera gagal jika tidak ada aturan di lokasi itu atau di lokasi induk yang memberikan akses. Bahkan jika setiap jalur anak yang terpengaruh dapat diakses, membaca di lokasi induk akan gagal sepenuhnya. Pertimbangkan struktur ini:

{
  "rules": {
    "records": {
      "rec1": {
        ".read": true
      },
      "rec2": {
        ".read": false
      }
    }
  }
}

Tanpa memahami bahwa aturan dievaluasi atom, mungkin tampak seperti saat mengambil /records/ path akan kembali rec1 tapi tidak rec2 . Namun, hasil sebenarnya adalah kesalahan:

JavaScript
var db = firebase.database();
db.ref("records").once("value", function(snap) {
  // success method is not called
}, function(err) {
  // error callback triggered with PERMISSION_DENIED
});
Objective-C
Catatan: Produk Firebase ini tidak tersedia pada target Clip App.
FIRDatabaseReference *ref = [[FIRDatabase database] reference];
[[_ref child:@"records"] observeSingleEventOfType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  // success block is not called
} withCancelBlock:^(NSError * _Nonnull error) {
  // cancel block triggered with PERMISSION_DENIED
}];
Cepat
Catatan: Produk Firebase ini tidak tersedia pada target Clip App.
var ref = FIRDatabase.database().reference()
ref.child("records").observeSingleEventOfType(.Value, withBlock: { snapshot in
    // success block is not called
}, withCancelBlock: { error in
    // cancel block triggered with PERMISSION_DENIED
})
Jawa
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference ref = database.getReference("records");
ref.addListenerForSingleValueEvent(new ValueEventListener() {
  @Override
  public void onDataChange(DataSnapshot snapshot) {
    // success method is not called
  }

  @Override
  public void onCancelled(FirebaseError firebaseError) {
    // error callback triggered with PERMISSION_DENIED
  });
});
ISTIRAHAT
curl https://docs-examples.firebaseio.com/rest/records/
# response returns a PERMISSION_DENIED error

Sejak operasi membaca di /records/ adalah atom, dan tidak ada membaca aturan yang memberikan akses ke semua data di bawah /records/ , ini akan melempar PERMISSION_DENIED kesalahan. Jika kita mengevaluasi aturan ini di simulator keamanan kami konsol Firebase , kita dapat melihat bahwa operasi membaca ditolak karena ada aturan read diperbolehkan akses ke /records/ path. Namun, catatan bahwa aturan untuk rec1 tidak pernah dievaluasi karena tidak di jalur kami meminta. Untuk mengambil rec1 , kita perlu mengaksesnya secara langsung:

JavaScript
var db = firebase.database();
db.ref("records/rec1").once("value", function(snap) {
  // SUCCESS!
}, function(err) {
  // error callback is not called
});
Objective-C
Catatan: Produk Firebase ini tidak tersedia pada target Clip App.
FIRDatabaseReference *ref = [[FIRDatabase database] reference];
[[ref child:@"records/rec1"] observeSingleEventOfType:FEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
    // SUCCESS!
}];
Cepat
Catatan: Produk Firebase ini tidak tersedia pada target Clip App.
var ref = FIRDatabase.database().reference()
ref.child("records/rec1").observeSingleEventOfType(.Value, withBlock: { snapshot in
    // SUCCESS!
})
Jawa
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference ref = database.getReference("records/rec1");
ref.addListenerForSingleValueEvent(new ValueEventListener() {
  @Override
  public void onDataChange(DataSnapshot snapshot) {
    // SUCCESS!
  }

  @Override
  public void onCancelled(FirebaseError firebaseError) {
    // error callback is not called
  }
});
ISTIRAHAT
curl https://docs-examples.firebaseio.com/rest/records/rec1
# SUCCESS!

Pernyataan yang Tumpang Tindih

Ada kemungkinan lebih dari satu aturan untuk diterapkan ke sebuah node. Dalam kasus di mana beberapa aturan ekspresi mengidentifikasi node, metode akses ditolak jika salah satu kondisi adalah false :

{
  "rules": {
    "messages": {
      // A rule expression that applies to all nodes in the 'messages' node
      "$message": {
        ".read": "true",
        ".write": "true"
      },
      // A second rule expression applying specifically to the 'message1` node
      "message1": {
        ".read": "false",
        ".write": "false"
      }
    }
  }
}

Dalam contoh di atas, membaca dengan message1 simpul akan ditolak karena aturan kedua adalah selalu false , meskipun aturan pertama selalu true .

Langkah selanjutnya

Anda dapat memperdalam pemahaman Anda tentang Aturan Keamanan Firebase Realtime Database:

  • Pelajari konsep utama berikutnya dari bahasa Aturan, dinamis kondisi , yang memungkinkan Aturan cek pengguna otorisasi Anda, membandingkan data yang ada dan masuk, memvalidasi data yang masuk, memeriksa struktur pertanyaan yang datang dari klien, dan banyak lagi.

  • Tinjau kasus penggunaan keamanan khas dan definisi Firebase Aturan Keamanan alamat mereka .