FirebaseのFirestoreのセキュリティルールの設定方法

Firestoreのセキュリティルール

Cloud Firestore セキュリティルールを使用すると、インフラストラクチャを管理したり、サーバー側の認証コードや承認コードを作成したりする必要がなくなるため、デベロッパーは優れたユーザー エクスペリエンスを構築することだけに集中できます。

Cloud Firestore 公式ドキュメントより

しかし、Firestoreのセキュリティルールは公式ドキュメントを見てもどう設定すれば良いのかわかりづらいので、よく使用されるルールを簡単にまとめました。

ルール プレイグラウンドで確認

設定したルールが正しく動作するかどうかはルール プレイグラウンドで確認できます。

ルールが問題なければ「シミュレートされた読み取りが許可されました」と表示されます。

Cloud Firestore ルール プレイグラウンドで確認

rules_versionは実質必須

デフォルトのルールには「rules_version」というのが最初に記載されている。

rules_version = '2';

service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write: if false;
    }
  }
}

これはCloud Firestore セキュリティルールのバージョンを指定するための設定です。

Cloud Firestore セキュリティルールのバージョン2は2019年5月以降に使用可能になりました。

公式ドキュメントのサンプルコードだと「rules_version = '2';」が記載されていないことがありますが、これが記載されていないとバージョンを固定できないので実質必須です。

※ この記事でも「rules_version = '2';」の記述は割愛します。

ユーザーの認証状態に基づいてアクセス制御

Firebase Authenticationでログイン中のみアクセス可能にする場合は「if request.auth != null;」という条件を使用する。

service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write: if request.auth != null;
    }
  }
}

もし、「foo@gmail.com」のアカウントでログインしたときのみに絞り込む場合は「request.auth.token.email」の条件を追加して判定する。

service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write: if request.auth != null &&
        request.auth.token.email == 'foo@gmail.com';
    }
  }
}

メールアドレスが複数ある場合は以下のようにします。

service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write: if request.auth != null && (
        request.auth.token.email == 'foo@gmail.com' || 
        request.auth.token.email == 'bar@gmail.com');
    }
  }
}

メールアドレスの後ろが@gmail.comに一致するときのみの場合は以下のようになります。

service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write: if request.auth != null &&
        request.auth.token.email.matches('.+@gmail\\.com$');
    }
  }
}

※ request.auth.token.email.endsWith('@gmail.com'); だと処理できません。

emailが一致するかで判定しましたが、以下のようにuidの一致で判定することもできます。

service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write: if request.auth != null &&
        request.auth.uid == 'o8TSldNqF4dRAMkmNMSl147t7Kd8';
    }
  }
}

AuthenticationのユーザーUIDはAuthenticationのページで確認するか、onAuthStateChangedでログイン時にconsole.logで調べることができます。

onAuthStateChanged(auth, (user) => console.log(user.uid))
// o8TSldNqF4dRAMkmNMSl147t7Kd8

ユーザーごとのドキュメントへのアクセス制限

前述までは全ドキュメントへのアクセス制限ですが、以下のようにrequest.auth.uidとuserIdが一致するパスだけにアクセスさせることが可能です。

service cloud.firestore {
  match /databases/{database}/documents {
    match /users/{userId} {
      allow read, write: if request.auth != null &&
        request.auth.uid == userId;
    }
  }
}