Edited at

超入門Firestore Security Ruleプログラミング


はじめに

Firebase初めてで且つ、Firestore入門時にSecurity Ruleを見て、なんじゃこれってなる方は多いかと思います。

Security Ruleも1つの言語として扱って法則や書き方、各スコープに暗黙的に追加される変数等を把握して抵抗をなく快適にSecurity Ruleプログラミングできたらいいなと思います。


ゴール

Security Ruleの書き方を学んでFirestoreをコードのバグや、クラッカーの驚異から守る。


1. ruleをwebconsoleで気軽に試す

firebaseで自身の練習用プロジェクトを選択して入り、Firestore console画面のルールタブをクリックする

画面はこんな感じになってるはず

スクリーンショット 2018-10-30 11.03.21.png


ruleをローカルで管理する

firebase、firestoreの環境構築済みを想定しています。

自身のプロジェクトにあるfirebase.jsonを開き、firestore項目のrule項目にfirestoreのsecurity ruleファイル名を指定します。



firebase.json

{

"firestore": {
"rules": "firestore.rules"
},
}

この場合、自身のfirebase.jsonと同じディレクトリにfirestore.rulesファイルを作成する

そうすれば以下コマンドでデプロイする時に一緒にルールもデプロイされる

$ firebase deploy

勿論以下のコマンドでruleだけをデプロイすることもできる

$ firebase deploy --only firestore:rules


余談

もちろんこのように好きな名前をつけることもできる


firebase.json

{

"firestore": {
"rules": "piyopiyo.rules"
},
}


ruleをローカルで管理する時に役立つツール

筆者は主にvscodeを使っていますが、vscodeにはFirebase開発をサポートするいくつかの拡張機能があります。

例: security rule周りを良い感じにしてくれるやつ

スクリーンショット 2018-10-30 11.07.27.png

これを入れると*.rulesがこんな感じにシンタックスされまる

スクリーンショット 2018-10-30 11.01.39.png

とても良い感じですね!


文法編

ではここからSecurity Ruleの基本的な文法に関して話していきます!


題材

今回はこのsecurity ruleを元に解説をしていきます。


firestore.rules

service cloud.firestore {

match /databases/{database}/documents {
function isAuthenticated() {
return request.auth != null;
}
function isMyDoc(userId) {
return request.auth.uid == userId;
}
match /user/{userId} {
allow read: if isAuthenticated();
allow write: if isMyDoc(userId);
}
match /privateuser/{userId} {
allow read, write: if isMyDoc(userId);
}
}
}


怖くないよ構文

実は今回のこのruleのサンプルは、Javascriptのシンタックスハイライトを使っています。

そう、security ruleの構文はJavascriptに凄く似ているんです!



なんじゃこれ!! その1

まずはこれなんだ!?ってなると思います。

実は調べてないので自分も知りませんが、まぁJavaとかのpublic void main的な奴じゃないかなと思います。

まぁ、知らなくてもコードに影響ないのでおまじないでいいでしょ! (もし知ってる人いたら教えてくれると嬉しいです☺


サンプル

service cloud.firestore {

match /databases/{database}/documents {
}
}



なんじゃこれ!! その2

これJSの関数じゃん!ってなると思います。

はい、関数構文のシンタックス全く同じです☺


サンプル

function isAuthenticated() {

return request.auth != null;
}



なんじゃこれ!! その3

このrequest変数ってなんじゃ!どこにも定義されてないぞ!ってなると思います。

はい、このrequest変数はブラウザのwindow変数とかと同じようにグローバルに元から埋め込まれている変数です!

え!じゃあ他にも色々と定義済みな変数ってあるの!?と身構えるかもしれませんが、きっと多分おそらくないと思います(2018/11/30日時点)。

参考にしたソースはこれです。

request変数はオブジェクトで色んなプロパティがとかが生えてます。

その辺も参考にしたソースのリンクを参照してください。


サンプル

function isAuthenticated() {

return request.auth != null;
}



この関数結局どういう意味じゃあ!

この関数はログイン判定をする関数です。

関数がtrueを返せばログイン済み、falseを返せば未ログインです。


サンプル

function isAuthenticated() {

return request.auth != null;
}



ログインしてるユーザーにしかこのドキュメント見せたくないんじゃあ!

isAuthenticatedでログイン判定ができるので以下のように使えばログインしてる人しかこのドキュメントは読み込めません。


サンプル

service cloud.firestore {

match /databases/{database}/documents {
function isAuthenticated() {
return request.auth != null;
}
match /user/{userId} {
allow read: if isAuthenticated();
}
}
}

これreadしか書いてないじゃん!この場合writeってどうなるの!?って思った方は鋭いです!

firestoreは基本このように誰に読み取り・書き込みの許可を出すのかを書かなければ基本全部禁止されています。

つまりこのコードの場合、全てのドキュメントへの書き込みは全ユーザーに禁止されているって事んです!とても安全でシンプルでしょう!



俺のドキュメントは俺が好きに書き込みたいんじゃあ!

本人のドキュメントかどうかを判定するにはこのルールは良い感じです。

ログインされていた場合、authにはuidがつきます。そのuidとアクセスしたドキュメントのuidが一致したら書き込みを許可しますよ!ってルールです。


サンプル


firestore.rules

service cloud.firestore {

match /databases/{database}/documents {
function isMyDoc(userId) {
return request.auth.uid == userId;
}
match /user/{userId} {
allow write: if isMyDoc(userId);
}
}
}


最後に

とりあえず自分の入門編としてはこの辺までにしようともいます。

この記法だけでも大体のニーズにあったルールはかけるんじゃないでしょうか。

当たり前ですが公式ドキュメントの方がとても詳細に書かれているので、もしこの内容を見てfirestoreのルール書いてみたい!って思って頂けましたら是非ともそちらもご参照ください。

また、自分が書いてるfirebase + vue.jsのサンプルコードもございますので、もしvue.js + firebaseで快適な開発してみたいって方がいましたら、ご参考にまでどうぞ

https://github.com/k-okina/book-management