当社ではFirebaseを認証基盤として採用することが多いのですが、ユーザーを複数ワークスペースに所属させたい場合のセキュリティルールを考えるのがやや大変でした。
この記事では、同じような悩みを持つ方の参考になるように、考えたことや調べたことを共有します。
なぜ大変なのか
Firestoreのセキュリティルール(v2)は最低限の関数や制御しかできず、複雑にセキュリティルールを記述することができません。
そのため、最初にデータモデルを適当に作ると全部バックエンドでどうにかするようにするしかなくなってしまう点が非常にツライです。
Cloud Functionsをガンガン採用する前提ならば良いかもしれませんが、せっかくFirebaseプラットフォームを使うのならばクライアントの処理だけサクッと書いて済むようにしたい方も一定数いると思います。
ただし、注意すべきなのは、セキュリティルールで守れないデータはもう守れないというほどセキュリティルールは非常に大事なので、あまりにも難しくて良いルール記述が思いつかない場合には諦めてCloud Functions等のバックエンド処理に任せるようにしましょう。おそらくルールを考え続けるよりは早く実装できるでしょう。
それでは、以下からアイデアを紹介していきます。紹介するアイデアを使えばほとんどのSaaSの要件を達成できる気がします。
とはいえ、細かいところはCloud Functions任せということにはなります。全てはプロジェクトによりますので、今回ご紹介するアイデアは万全ではありません。
前提
前提として、以下のデータを保存したいとします。
- users
- workspaces
- contents(workspaceに紐づく)
アイデア1 workspace_members
を作成し、ID文字列を工夫して対応する
新たなコレクションworkspace_membersを作成し、そのID文字列に一工夫を加えます。これはGPT-4が考えてくれたアイデアで、Googleで調べてもなかなか出てこないものです。
これはこのドキュメントIDの文字列を下記の構成にするというものです。
$(workspace_id)_$(user_id)
workspacesのドキュメントIDと、usersのドキュメントIDを_
で繋げるというものです。
こうすることで下記のようなルールを書けるのです。
allow delete: if
exists(/databases/$(database)/documents/users/$(request.auth.uid));
function isMember(teamId) {
let documentId = teamId + '_' + request.auth.uid;
return exists(/databases/$(database)/documents/workspace_members/$(documentId));
}