Buka konsol

Keamanan Berbasis Pengguna

Dokumen ini meninjau kembali konsep Mengamankan Data dengan memanfaatkan variabel auth yang telah ditetapkan untuk membuat solusi pengamanan data yang lengkap.

Mengintegrasikan Authentication

Firebase Authentication terintegrasi dengan Firebase Realtime Database agar Anda dapat mengontrol akses data pada basis per pengguna.

Setelah pengguna mengautentikasi, variabel auth dalam aturan Aturan Realtime Database akan diisi dengan informasi pengguna. Informasi ini berisi ID unik (uid) serta akun data yang tertaut milik pengguna, seperti ID Facebook atau alamat email, dan info lainnya. Jika mengimplementasikan penyedia autentikasi khusus, Anda dapat menambahkan kolom Anda sendiri ke payload autentikasi pengguna.

Panduan ini menjelaskan cara menggabungkan bahasa Aturan Firebase Realtime Database dengan informasi autentikasi tentang pengguna Anda. Dengan menggabungkan dua konsep ini, Anda bisa mengontrol akses ke data berdasarkan identitas pengguna.

Variabel auth

Variabel auth yang telah ditetapkan dalam aturan adalah null sebelum autentikasi dilakukan. Jika pengguna sudah diautentikasi dengan Firebase Authentication, maka variabel tersebut akan berisi atribut berikut:

penyedia Metode autentikasi yang digunakan ("sandi", "anonim", "facebook", "github", "google", atau "twitter").
uid ID pengguna yang unik, harus unik di semua penyedia.
token Isi token ID Firebase Auth. Lihat dokumen referensi mengenai auth.token untuk mendapatkan informasi selengkapnya.

Berikut adalah contoh aturan yang menggunakan variabel auth untuk memastikan bahwa setiap pengguna hanya dapat menulis ke lokasi khusus pengguna:

{
  "rules": {
    "users": {
      "$user_id": {
        // grants write access to the owner of this user account
        // whose uid must exactly match the key ($user_id)
        ".write": "$user_id === auth.uid"
      }
    }
  }
}

Membuat Struktur Database Anda

Membuat struktur database dengan cara yang memudahkan penulisan aturan keamanan terkadang dapat bermanfaat. Sebagai contoh, salah satu pola umum untuk menyimpan data pengguna di Realtime Database adalah dengan menyimpan semua pengguna di satu node users, yang turunannya merupakan nilai uid untuk setiap pengguna. Jika Anda ingin membatasi akses ke data ini sehingga hanya pengguna yang login yang bisa melihat data mereka, aturannya akan terlihat seperti ini:

{
  "rules": {
    "users": {
      "$uid": {
        ".read": "auth != null && auth.uid == $uid"
      }
    }
  }
}

Bekerja dengan Klaim Khusus Authentication

Untuk aplikasi yang memerlukan kontrol akses khusus untuk pengguna yang berbeda, Firebase Authentication memungkinkan developer menetapkan klaim pada pengguna Firebase. Klaim ini dapat diakses dalam variabel auth.token di aturan Anda. Ini adalah contoh aturan yang menggunakan klaim khusus hasEmergencyTowel:

{
  "rules": {
    "frood": {
      // A towel is about the most massively useful thing an interstellar
      // hitchhiker can have
      ".read": "auth.token.hasEmergencyTowel === true"
    }
  }
}

Developer yang membuat token autentikasi khusus bisa menambahkan klaim ke token tersebut secara opsional. Klaim ini tersedia pada variabel auth.token di aturan Anda.

Meninjau Kembali Contoh Chat

Mari membuat contoh chat dari Mengamankan Data Anda dan menambahkan beberapa autentikasi pengguna, yang menerapkan semua konsep ini ke dalam aplikasi yang bekerja:

{
  "rules": {
    "room_names": {
      // any logged in user can get a list of room names
      ".read": "auth !== null",

      "$room_id": {
        // this is just for documenting the structure of rooms, since
        // they are read-only and no write rule allows this to be set
        ".validate": "newData.isString()"
      }
    },

    "members": {
       // I can join or leave any room (otherwise it would be a boring demo)
       // I can have a different name in each room just for fun
       "$room_id": {
          // any member can read the list of member names
          ".read": "data.child(auth.uid).exists()",

          // room must already exist to add a member
          ".validate": "root.child('room_names/'+$room_id).exists()",

          "$user_id": {
             ".write": "auth.uid === $user_id",
             ".validate": "newData.isString() && newData.val().length > 0 && newData.val().length < 20"
          }
       }
    },

    "messages": {
      "$room_id": {
        // the list of messages for a room can be read by any member
        ".read": "root.child('members/'+$room_id+'/'+auth.uid).exists()",

        // room we want to write a message to must be valid
        ".validate": "root.child('room_names/'+$room_id).exists()",

        "$message_id": {
          // a new message can be created if it does not exist, but it
          // cannot be modified or deleted
          // any member of a room can write a new message
          ".write": "root.child('members/'+$room_id+'/'+auth.uid).exists() && !data.exists() && newData.exists()",

          // the room attribute must be a valid key in room_names/ (the room must exist)
          // the object to write must have a name, message, and timestamp
          ".validate": "newData.hasChildren(['user', 'message', 'timestamp'])",

          // the message must be written by logged in user
          "user": {
             ".validate": "newData.val() === auth.uid"
          },

          // the message must be longer than 0 chars and less than 50
          "message": { ".validate": "newData.isString() && newData.val().length > 0 && newData.val().length < 50" },

          // messages cannot be added in the past or the future
          // clients should use firebase.database.ServerValue.TIMESTAMP
          // to ensure accurate timestamps
          "timestamp": { ".validate": "newData.val() <= now" },

          // no other fields can be included in a message
          "$other": { ".validate": false }
        }
      }
    }
  }
}

Langkah Berikutnya