firestoreのセキュリティルール設定(firebaseでユーザー・役割ごとの権限制御)

投稿者: | 2019年4月21日

firebaseでセキュリティどんな設定できんの?って話です。

firebaseで転職サイトみたいなものを友人たちと作っているのですが、我々の転職サイトでは権限が異なる3種のユーザーが使うサイトになるので、権限設定回りが重要になります。その複雑な権限設定をfirebaseのセキュリティルールでやってみました。

前提:権限パターン

3つの役割(role)+所有者 => 4種の権限

役割 意味
1.admin 管理者。なんでもできる。
2.company 会社用アカウント。ユーザー情報の参照ができる。
3.user 一般ユーザー。ほかのユーザー情報は閲覧不可。求人票は見れる。

上記役割にプラスして各情報の所有者という概念も使ってます。(ユーザーは自分が所有者の登録情報は閲覧・更新可能とかに使います。)

なので役割3つ+所有者になるので4種の権限が混在することになります。

役割ごとの出来ること整理

複雑なので表にしてみました。(それでも複雑に…)

  • 大きくWebサイトで管理する情報は、ユーザー情報、会社情報の2種。それぞれ所有者が設定され、情報の更新は所有者しかできない。
  • userは他人のユーザー情報の参照はできない。会社情報の中で公開中の情報のみしか参照できない。
  • companyはユーザー情報も会社情報も閲覧できるが、個人情報などのシークレット情報は見れない。
  • 管理者は何でもできる。(開発中だからね…)

firebaseのfirestoreセキュリティルールでやるべきこと

表にしたりと長ったらしい前提を書きましたが、firestoreのセキュリティルールでは大きく以下の2つが実現できれば上記の権限設定が実現できると考えました。(そして出来ました。)

  1. アクセスしたユーザーが、参照対象のレコードの所有者かどうかの判定
  2. アクセスしたユーザーが、要求しているレコード/アクションが可能な役割かの判定

では、それぞれのやり方を記載します。

① アクセスしたユーザーが、参照対象のレコードの所有者かどうかの判定

service cloud.firestore {
  match /databases/{database}/documents {      
    match /user/{userId} {
      function isOwner() {   
          return request.auth.uid == userId;
      }
   
      allow update, delete: if isOwner();
      allow create: if request.auth.uid != null;
      allow read: if isOwner();
    }
  }
}

これが一番簡単かなと。コレクション「user」のドキュメントIDをauthenticationのユーザーのIDであるUIDを設定しておき、request.auth.uidと比較します。

ただ、この方法だと全ての権限を設定したいコレクションのIDをUIDにする必要があり、レコード単位に柔軟性がありません。使いやすいやりかたとしては以下があります。

service cloud.firestore {
  match /databases/{database}/documents {      
    match /user/{userId} {
      function isOwner() {   
          return request.auth.uid == resource.data.uid; // ここを変更
      }
   
      allow update, delete: if isOwner();
      allow create: if request.auth.uid != null;
      allow read: if isOwner();
    }
  }
}

firebaseのセキュリティルールでは「resource」を指定することでアクション対象のレコードデータを参照することが可能です。アクションと言っているのは、参照、更新、削除すべて含みます。

「resource.data.uid」と指定することで、アクション対象のレコードのUIDを取得るすることができ、アクセスしたユーザーのUIDと比較することが可能です。このやり方であれば、各コレクションにUIDをカラムとして追加しておけば権限判定ができますので柔軟に組み込むことができおススメです。

② アクセスしたユーザーが、要求しているレコード/アクションが可能な役割かの判定

前提として、以下のコレクションをfirestoreに作成していると考えてください。

  • コレクション名「userRole」
  • ドキュメントのID:uid
  • ドキュメントに格納するオブジェクト:role (user, company, adminの3種が設定される)
service cloud.firestore {
  match /databases/{database}/documents {    
    function isAdmin() {   
        return get(/databases/$(database)/documents/userRole/$(request.auth.uid)).data.role == "admin";
    }

    function isCompany() {   
        return get(/databases/$(database)/documents/userRole/$(request.auth.uid)).data.role == "company";
    }
    
    match /user/{userId} {
      function isOwner() {   
          return request.auth.uid == userId;
      }
   
      allow update, delete: if isOwner() || isAdmin();
      allow create: if request.auth.uid != null;
      allow read: if isOwner() || isAdmin() || isCompany();
      
      match /secret/{docId} {
      	allow read, write: if isOwner() || isAdmin();
      }
    }
  }
}

こんな感じです!

「get(/databases/$(database)/documents/userRole/$(request.auth.uid)).data.role」のように記載することで、firestore上の任意のドキュメントにアクセスし、データを参照することができます。userRoleコレクションに登録されているユーザーごとのroleを参照することで、アクセスのあったユーザーの役割を取得し、役割に従ったセキュリティルールを設定することが可能になります。

さいごに

firebaseとても便利だなと感じました。こんなレコード単位とか役割ごとの権限設定を一から構築するとなると何か月もかかりそう…

 


カツオが開発したWebサービスです。

「セールサーチ」ネットショップのセール情報の検索サイト!

平成の想い出を気軽に年表にしてシェアすることができるサービスです。ぜひ使ってみてください。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です