🔐

Firestoreのセキュリティルールでフィールドの値を利用する【Firebase】

に公開

🔥 導入

とあるアプリプロジェクトでfirestoreのセキュリティルールを設定していたのですが、
その際にドキュメント内のフィールドの値によって権限を変更する、という仕様がありました。
その時に調べたことのメモ。
特にフィールドがReference型である場合の扱いで沼ったので、その備忘録として。

🔍 対象

  • Firestoreのセキュリティルールの基本的な書き方がわかる
  • Firesotreのセキュリティルールで、ドキュメントのフィールドの値を利用したい

✅ 結論

フィールドの値は以下のように使います。

// String型を利用
allow write: if resource.data.name == 'Alice';

// int型を利用
allow write: if resource.data.number > 5;

// bool型を利用
allow write: if resource.data.isDelete == false;

// Reference型を利用
allow write: if get(resource.data.docRef).id == request.auth.uid;

🧐 resourceとrequest.resourceの違いについて

ドキュメントのフィールドを利用する際、
resourceとrequest.resourceが利用できます。

プロパティ 役割 使用シーン
resource 現在Firestoreに保存されているデータ 既存のドキュメントのデータを確認するとき
request.resource リクエストされた(更新・作成しようとしている)データ 新しく書き込むデータを検証するとき

使い分け

ケース resource request.resource
読み取るデータ 既にFirestoreに保存されているデータ ユーザーが送信しようとしているデータ
いつ使うか readやupdateの前のデータチェック createやupdateの新しいデータの検証
使える操作 read, update, delete create, update

⚠️ Reference型の扱いに注意

フィールドの値は基本的にそのまま利用できます。

公式ドキュメントにも記載があります。

https://firebase.google.com/docs/firestore/security/rules-conditions?hl=ja#data_validation
Stiring型やint型はそのまま利用していますね。

抜粋1

match /cities/{city} {
  allow read: if resource.data.visibility == 'public';
}

抜粋2

match /cities/{city} {
  allow update: if request.resource.data.population > 0
                && request.resource.data.name == resource.data.name;
}

そのため、私はReference型も以下のようにして利用しようとしたのですが...なぜかパーミッションエラーが出る。

以下の例の前提

トップレベルコレクションとして、userコレクションと、postコレクションがあり
postドキュメントには、誰が投稿したのものかがわかるように、userコレクションへの参照を保存するcreateuserRefフィールドがあると仮定。

├── user/
│   ├── {userID}/
│   │   ├── name: String
│   │   ├── age: int
├── post/
│   ├── {postId}/
│   │   ├── createuserRef: Reference
│   │   ├── contentText: stirng
│   │   ├── createdAt: timestamp
match /post/{postId} {
    allow update: if request.resource.createuserRef.id == request.auth.id;
}

Reference型はgetする!

Reference型を利用する際は必ずgetしましょう!!

match /post/{postId} {
    allow update: if get(request.resource.createuserRef).id == request.auth.id;
}

ちなみにReference型として利用できるので、、、
get(request.resource.createuserRef).pathを使えるようです。

🔖 最後に

Firestoreのセキュリティルールをしっかりと設定して、より良いアプリライフを!
間違えている部分等あったらご教授いただけると幸いです!!

Discussion