ルールを知ろう

おまとめ三行

セキュリティルールの書き方を何パターンか
ぼうけんのしょが消えちゃうくらいやばいです
基本はこんなとこでしょう
以前、FirestoreのRealtime Databaseの使い方をざっとやりましたが、あの時は誰でも全てのデータを自由に読み書きできるという状態だったので、今日はセキュリティルールの書き方を何パターンか見てみたいと思います。



前提条件

とりあえず現状ではデータベースの中身がこんな風になってると仮定します。

norm-nois
  │  
  ├ users
  |  ├ 1 
  |  |  ├ name : 佐藤
  │  |  └ age : 30
  │  └ 2
  |     ├ name : 佐藤
  │     └ age : 30
  │  
  └ tweets
     ├ 1 
     |  └ text : hello
     └ 2
        └ text : hogehoge

MySQLっぽくイメージするなら、usersやtweetsというテーブルがあって、その中にnameやage、textというカラムがあってレコードが登録されている、みたいな感じです。



誰でも読み書きできる

まずは前回でも設定した、誰でもどのデータでも読み書きができる状態。

{
  "rules": {
    ".read": true,
    ".write": true
  }
}

まさしくどんなデータにでもアクセスできるので、うっかり消しちゃいけないデータを上書きしてしまうリスクなどがあります。

例えばうっかりこんなコードを実行してしまうと、データが全部上書きされてしまいます。

firebase.database().ref().set({test:'aaaa'});

//実行後のデータベースの中身
norm-nois
  |
  └ test : aaaa

usersもtweetsもごっそり上書きされてなくなっちゃう。これはまずいですね。ドラクエでクリア直前の状態でセーブしといたぼうけんのしょが消えちゃうくらいやばいです。



読み込めるけど書き込めない

というわけで、うっかり上書きされないために読み込みだけ誰でもできるように設定を変更してみる。

{
  "rules": {
    ".read": true,
    ".write": false
  }
}

これで書き込みができなくなります。先ほどのコードを実行してもデータが上書きされることはない。

ただしこの設定だと一切の書き込みが禁止されるので、当然ながら新規にデータを追加することもできません。



特定の場所だけ書き込める

今度はusers以下だけは好きに書き込めるようにしてみる。

{
  "rules": {
    ".read": true,
    "users" : {
      ".write": true
    }
  }
}

これでusersの下にだけデータの追加、更新ができるようになる。tweetsの方には書き込めません。tweets以外もダメ。

//書き込める
firebase.database().ref('/users/100').set({name:'小林'});

//書き込めない
firebase.database().ref('/tweets/100').set({text:'やっほー'});
firebase.database().ref('/test').set('aaaa');
firebase.database().ref().set({test:'aaaa'});

こうしておけばうっかりtweetsの方のデータを上書きしてしまうミスは防げます。でもこの場合だとusersが丸々上書きされてしまうリスクはある。

firebase.database().ref('/users').set({name:'小林'});

//実行後のデータベースの中身
norm-nois
  │  
  ├ users
  |  └ name : 小林
  │  
  └ tweets
     ├ 1 
     |  └ text : hello
     └ 2
        └ text : hogehoge



IDがあるデータだけ書き込める

ではさらに突っ込んで、ユーザーIDがある場合にのみusersの下にデータを書き込める設定にしてみます。

{
  "rules": {
    ".read": true,
    "users" : {
      "$id": {
        ".write": true
      }
    }
  }
}

「$id」というのはワイルドカード的な変数です。変数名は別に何でも良いです「$userId」でも「$hoge」でも「$dragonquest」でも同じ。ようはこの変数を指定することで「users/{user_id}」というデータじゃないと書き込み権限が与えられないということです。

//書き込める
firebase.database().ref('/users/100').set({name:'小林'});
firebase.database().ref('/users/abcde').set({name:'小林'});

//書き込めない
firebase.database().ref('/users').set({name:'小林'});
firebase.database().ref('/tweets/100').set({text:'やっほー'});

これならusers全体のデータをうっかり上書きしちゃう心配もないですね。



認証済みのユーザーだけ書き込める

FirebaseにはAuthenticationというユーザー管理機能があります。ここで追加したユーザーだけが書き込めるようにもできます。

{
  "rules": {
    ".read": true,
    "users" : {
      "$id": {
        ".write": "auth != null"
      }
    }
  }
}

これでログイン状態の端末(ブラウザ)からだけ書き込みが可能になります。

ログインするには以下のコードを実行します。

firebase.auth().signInWithEmailAndPassword('メールアドレス', 'パスワード');

メールアドレスとパスワードはAuthenticationでユーザーを追加した時のメールアドレスとパスワードです。これを自分のブラウザで任意のページにアクセスした時に実行すればログインが完了し、データの書き込みが可能になります。

ログインしているかどうかは以下のコードで確認できます。

firebase.auth().onAuthStateChanged(function(user){
  console.log(user);
});

ログインしていればuserにデータが入ってきます。



特定のユーザーだけ書き込める

先ほどの設定だとどのユーザーでログインしても書き込みができるようになりますが、特定のユーザーでログインした時だけ書き込めるようにすることもできる。

{
  "rules": {
    ".read": true,
    "users" : {
      "$id": {
        ".write": "auth.uid == 'ユーザーUID'"
      }
    }
  }
}

ユーザーUIDはAuthenticationのページで確認できます。

authentication

ユーザーを追加するとここにUIDが表示されるので、これで書き込み可能なユーザーを指定することができます。






細かく設定しようと思えばもう少しいろんな設定があるのですが、基本はこんなとこでしょう。その他の設定についてはここを参照。

Firebase Realtime Database ルールについて

Realtime DatabaseにはMySQLのテーブルみたいな概念がないので、本格的に運用するってなったらこういうルールを決めて不用意にデータが消えたりしないようにはしといた方が良いんじゃないかなと思います。自分のユーザーデータだけ上書きできるようにしたりとかね。



その他のFirebaseに関する記事はこちら