Firestoreセキュリティルール設定

Firestoreを使うことによってセキュリティールールを設定する必要があります!

基本設定からご説明します
firestore.rulesのファイルでルールの管理ができる。ローカル環境でFirestoreのエミュレーターが起動している時に動的に読み込んで更新してくれる。

2020年7月の時点でバージョンは2となっていますが、
Firebaseの公式ドキュメントによるバージョンをチェックしましょう。

Get started with Cloud Firestore Security Rules | Firebase
With Cloud Firestore Security Rules, you can focus on building a great user experience without having to manage…

FirebaseとGCPで様々なルール設定があるので、スコープを設定するためバージョン指定のあとセキュリティルールの設定をする。matchの中で全ルールを書く。

service cloud.firestore {
  match /databases/{database}/documents {
    //
  }
}

Firestoreのセキュリティールールはホワイトリストの仕組みとなっている。

Firestoreにリクエストが来たら、許可しているルールが存在しない限りではデータを読み込みと書き込みができない。

ルールで様々インターフェースがあり、主に使うのはrequestのプロパティー。

Interface: Request | Firebase
AnalyticsUserPropertyAllowAdPersonalizationSignals

リクエストの認証情報と比較したい時にrequest.authでそれぞれの情報を取得できる。書き込みのルールでリクエストデータをバリデートする時にrequest.resource.data.<データ名>で取得できる。

ルールは読み込みと書き込みに分けていて、さらに読み込みはGetとListに分けられている。また、書き込みはCreate・Update・Deleteに分けられている。
シンプルなルールを書いてみましょう。

ログイン済みのユーザーのみの読み込み許可のルールを書きましょう。

match /consumedFoods/testFood {
     allow read: if request.auth != null;
}

上記の書き方でtestFoodのドキュメントのみ読み込みは可能となる。
できるだけルールを細かく書いたほうが管理しやすい。
スコープを広げて、全ドキュメンとへ影響するルールの設定もできる。

match /consumedFoods/{foodId}

指定コレクション配下のドキュメントに対してルールが適用される

match /{documentID=**}

上記の書き方をすると全てのデータに対して条件を書くので、要注意だ。

サブコレクションがある場合ドキュメントの許可を設定しても、サブコレクションのデータを読み込めない。

  // ドキュメントの条件
  allow read: if request.auth != null
  match /{allChildren=**} {
   // サブコレクションの条件
   allow read: if request.auth != null || request.auth == null;
  }
}

このように条件を分けることにより、認証済みユーザがconsumedFoods Collectionの DocumentとSubCollectionの読み込みが許可される。
それに加えて、未認証ユーザに対して
consumedFoodsのSub Collectionにのみ読み込み権限を与えることができる

次にルールで使う関数の書き方を説明していきます!

色々なデータに同じ条件を使う場合関数化をするのが便利です。
例えば、フォームに入力された値のフォーマットと必須チェックするため関数を用意しました。

 // ↑書き込みの対象ドキュメント
  function isValidEmail() {
    return (request.resource.data.email.size() > 0 &&  
      request.resource.data.email.matches('.+@.+'))
    }
  
  allow create:
   // ↑createで作成のみの許可となる
    if isValidEmail();
}

文字列に対するルールにmatchesのメソッドがあり、正規表現と比較ことができます。
https://firebase.google.com/docs/reference/rules/rules.String
同じくsizeのメソッドで文字列の長さをチェックできます。バイトで計算されるので、マルチバイトの文字列だと要注意です。

全体的なルールを組み合わせるとこんな感じになります!

service cloud.firestore {
     match /databases/{database}/documents {
        match /consumedFoods/{foodId}/{allChildren=**} {
            function isAdmin() { 
                return request.auth.uid != null;
            }
            // サブコレクションとドキュメントの権限条件は一緒の場合
            allow read: if isAdmin()
        }
        match /consumedFoods/{foodId} {
            // ドキュメントの条件
            allow read: if request.auth != null
            match /{allChildren=**} {
                // サブコレクションの条件
                allow read: if request.auth != null || request.auth         == null;
            }
        }
        match /public/users/newApplication/{newUserDocument} {
        // ↑書き込みの対象ドキュメント
            function isValidEmail() {
                return (request.resource.data.email.size() > 0 &&  
                    request.resource.data.email.matches('.+@.+')
                )
            }
    
            allow create:
            // ↑createで作成のみの許可となる
                if isValidEmail();
        }
    }
}

対象プロジェクトにルールをデプロイするとFirebase ConsoleのCloud FirestoreのRulesタブに表示されている。そして、適用するため公開をする必要はある。

Firestoreのルールの設定による様々なことができるので、便利な機能です!