Firestoreのセキュリティルールを設定してSNSのホームとタイムラインを実現する

# Firestoreとは
Google社が提供する「Cloud Firestore」(以降Firestore)という名称のサービスで、一定量までは無料枠で利用できます。
Firestoreがどういうものかというと、公式ドキュメントから引用すると一言でなら以下です。
>Cloud Firestore は NoSQL のドキュメント指向データベースです。 SQL データベースとは異なり、テーブルや行はありません。代わりに、コレクションに編成されたドキュメントにデータを保存します。

使い始めるための公式ドキュメントはこちら。

https://firebase.google.com/docs/firestore/quickstart

# Firestoreのセキュリティルールとは
Firebase Console画面の以下のルールタブで設定できるやつです。
![Firestore _console.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/545703/c490349d-5a6d-31e1-852a-d5a8b852319e.png)

詳細について公式ドキュメントはこちら。

https://firebase.google.com/docs/firestore/security/get-started

今回はこのセキュリティルールを設定することで、SNSのようなホーム画面とタイムライン画面の表示を実現する部分にフォーカスして説明しようと思います。

# 完成イメージ
最初に完成イメージを示すと以下のようになります。
左側がログイン前で、右側がログイン後になります。
![Firebase_login_logout.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/545703/0ee9abff-88f8-65c4-b887-d60744248f69.png)
- ホーム画面
ログアウト状態では何のデータも参照できませんが、ログインすることで自身の投稿データの参照と変更などができるようになります。
- タイムライン画面
ログインをしなくても自分だけでなく他のユーザーも投稿参照出来るようになっています。

実際のアプリはこちら。無料ですので是非使ってみて下さい。

https://play.google.com/store/apps/details?id=com.highcom.growing_sake

# Firestoreのデータ構造
上記のような画面表示を実現するために、Firestoreのデータ構造は以下のようになっています。
![Firestoreデータ構造.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/545703/7b60076e-acbe-2f75-7517-a8a6df7a298a.png)
##### ホーム画面側のデータ
- HomeData
ホーム画面に表示するためのルートのCollectionになっていて、UserListのDocumentが1つだけ格納されています。
- UserList
この配下には、各ユーザーのCollectionをリストで保持しています。
- xxxUser、yyyUser、...
各ユーザーのCollectionには、ユーザーが投稿したデータをそれぞれのDocumentとして持っています。
- xxxDoc、yyyDoc、zzzDoc、...
各Documentには、タイトルや画像のURLをフィールドとして格納しており、これらのデータを読み出すことでホーム画面でのデータの表示を実現しています。
##### タイムライン画面側のデータ
- Timeline
タイムライン画面に表示するためのルートのCollectionになっていて、この配下に各ユーザーが投稿したDocumentを持っています。
- abcDoc、bcdDoc、cdeDoc、...
各ユーザーがデータを登録する際に、HomeData側と一緒にTimeline側に同じデータを登録するようにしており、ユーザーのデータが時系列に登録されています。

# Firestoreのセキュリティルール
上記のデータ構造を基にしてセキュリティルールを以下のように記載しました。
```sh
rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /Timeline/{document=**} {
    	allow read: if true;
    }
    match /HomeData/UserList/{userId}/{document=**} {
      allow read, write: if request.auth != null && request.auth.uid == userId;
    }
  }
}
```

##### ホーム画面側のセキュリティルール
ホーム画面はログアウト状態では参照できず、ログインすると参照＆変更が可能となっていました。
それを実現するために記載している箇所は以下となります。
```sh
    match /HomeData/UserList/{userId}/{document=**} {
      allow read, write: if request.auth != null && request.auth.uid == userId;
    }
```

- `{userId}`は、ログインしたユーザーのIDを指定する事が出来ます。
- `{document=**}`は、`{userId}`配下のすべでのDocumentを対象とします。
- `allow read, write:`は、参照と変更についての許容するルールを定義します。
- `if request.auth != null && request.auth.uid == userId;`は、ログイン認証されていてかつ、ユーザーIDが一致する場合を定義しています。
ここでいうログイン認証は、Firebase Authenticationを利用した認証のログインを指します。

https://firebase.google.com/docs/auth

##### タイムライン画面側のセキュリティルール
タイムライン画面はログイン／ログアウト状態に関わらず、全てのユーザーのデータを参照可能となっていました。
それを実現するために記載している箇所は以下となります。
```sh
    match /Timeline/{document=**} {
    	allow read: if true;
    }
```

- `{document=**}`は、`Timeline`配下のすべでのDocumentを対象とします。
- `allow read: if true;`は、条件無く参照は可能であることを定義しています。

# さいごに
以上でFirestoreのセキュリティルールについての説明は終わりとなります。
このようなセキュリティルールを設定することで、ログイン認証された本人だけが参照や変更できるようにアクセスを制限したり、他のユーザーのデータは参照だけしかできないような制限を設けることができました。
クラウド上でデータを扱う場合には、不用意にデータが変更されないように気を付ける必要があります。
セキュリティルールをしっかり記載することは重要です。