1. HOME
  2. ブログ
  3. IT技術
  4. テスト駆動で学ぶ Firestore セキュリティルール 【データ比較編 / 前編】

テスト駆動で学ぶ Firestore セキュリティルール 【データ比較編 / 前編】

テスト駆動で書籍コレクションのルールを実装する

この記事では、前編・後編の二回に分けて、Firestore セキュリティルール中でのデータ比較について解説していきます。

書店のネットショッピングサービスを想定し、Firestore 上の書籍コレクションのルール実装を例に、解説を進めていきます。

前回のデータ検証編では、主にリクエストデータやデータベース上のデータの参照について解説しました。

今回の記事では、より具体的に、データの数値比較やデータ型のチェックについて解説していきます。

データ検証編の記事はこちら

簡単な流れ

「データ比較編」では、以下のような流れで解説を進めていきます。

データ比較編:前編

  1. 書籍コレクションの要件を設定
  2. テスト環境の準備
  3. テストデータの作成
  4. Firestore 上のデータ追加ルールの実装と解説

データ比較編:後編

  1. Firestore 上のデータ更新ルールの実装と解説
  2. Firestore 上のデータ取得ルールの実装と解説
  3. 全体テストで要件の最終チェック
  4. まとめ

今回は、前編パートの、「実装目標(要件)の設定からデータ追加ルールの実装まで」を解説していきます。

書籍コレクションの実装目標

書籍コレクション books を想定し、以下の要件を目標に実装を進めていきます。

書籍データ追加・更新の要件

  1. データ追加・更新をリクエストしたユーザが商品管理者でない場合は追加・更新不可
  2. データのサイズが「9」でない場合は追加・更新不可
  3. タイトルが string 型でない場合は追加・更新不可
  4. 書籍詳細が string 型でない場合は追加・更新不可
  5. 出版日が timestamp 型でない場合は追加・更新不可
  6. 価格が int 型で「0」以上でない場合は追加・更新不可
  7. 在庫が int 型で「0」以上でない場合は追加・更新不可
  8. 状態が new, used のいずれかでない場合は追加・更新不可

商品管理者に対する要件

ここで、商品管理者がデータ更新することを想定し、商品管理者に対する要件を以下のように補足します。

▼データ追加では、「リクエストデータの商品管理者にリクエストユーザが存在する」ものとします。

▼データ更新では、「データベース上のデータの商品管理者にリクエストユーザが存在する」ことを要件とします。

データの取得要件

  1. 下書きデータの取得不可
  2. 在庫が「5」以下の書籍は取得不可

在庫が「5」以下の場合は、店頭販売のみを行うと仮定し、取得不可としています。

前準備 ~ テスト環境 ~

初めに、テスト環境を準備します。

テスト環境のセットアップ

以下のコマンドを実行して、テスト環境をセットアップしてください。

なお、今回の記事のコードは、以下のリポジトリにまとめてあります。

【GitHub】
rightcode/firestore-security-rules-test_data-compare

npm パッケージのインストール

以下のコマンドを実行して、必要となる npm パッケージをインストールしてください。

Firebase CLI ツールのインストール

まだ、Firebase CLI ツールをインストールしていない場合は、以下のコマンドを実行してインストールします。

Firestore エミュレータを起動

そして、コマンドを実行して、Firestore エミュレータを起動してください。

以上で、テスト環境の準備は完了です!

テスト環境のセットアップの解説

なお、テスト環境のセットアップについて、より詳細な内容は、以下の記事をお読みください!

コードをチェックアウトする

今回の記事で解説するコードを確認する場合は、以下のコマンドより「master ブランチ」をチェックアウトしてください。

「master ブランチ」に実装済みのコードを設置してあります。

※注意※
コードの調整などにより、この記事の内容とは、記述が一部異なる場合があります。

前準備 ~ テストデータ ~

テストを作成する前に、まず、テストデータ用のコードを用意します。

tests/data.ts ファイルを作成して、以下のように記述してください。

テストデータのコード

テストデータの概要

adminUser

テストで対象となる、書籍データの商品管理者の1人として定義。

データの追加・更新が可能なユーザとして使用します。

initialData

初期データ。

データ追加テストでのデータ追加と、更新・取得テスト前の初期データの準備に使用します。

validUpdateData

更新テスト用データ。

要件に沿ったデータで、データの更新に使用します。

Firestore 上のデータ追加ルールの実装

データ追加の要件

データ追加ルールのテストを作成する前に、まずは、データ追加の要件を再確認します。

  1. データ追加をリクエストしたユーザが商品管理者でない場合は追加不可
  2. データのサイズが「9」でない場合は追加不可
  3. タイトルが string 型でない場合は追加不可
  4. 書籍詳細が string 型でない場合は追加不可
  5. 出版日が timestamp 型でない場合は追加不可
  6. 価格が int 型で「0」以上でない場合は追加不可
  7. 在庫が int 型で「0」以上でない場合は追加不可
  8. 状態が new, used のいずれかでない場合は追加不可

ここで、一番上の商品管理者に関する要件については、「リクエストデータの商品管理者にリクエストユーザが存在する」ことが要件となります。

テストの作成

上記の要件に沿って、テストを作成します。

tests/data.add.test.ts ファイルを追加して、以下のようにコードを記述してください。

テストのコード

テストの概要

「データ追加をリクエストしたユーザが商品管理者でない場合は追加不可」となるテスト

商品管理者に含まれないユーザとして、 non_admin_user で認証したクライアントを取得しています。

「データのサイズが「9」でない場合は追加不可」となるテスト

リクエストデータのサイズを変更するため、初期データに author フィールドを追加しています。

型のチェックテスト

各テストのデータ追加リクエストの前に、初期データを調整して、不適切な型の値を設定しています。

ルールの実装

データ追加ルール用のテストが完成したので、このテストに沿ってセキュリティルールを実装していきます。

テスト駆動のスタイルに従い、まずはテストを実行してみて、テストが失敗することを確認します

全ての create アクセスを許可するセキュリティルールを設定

今回は、少しだけルールの実装を進めて、 create アクセスを全て許可するところからスタートします。

books コレクションの create アクセスを全て許可し、「要件にあったデータの追加に成功」するテストだけを通します。

その上で、失敗した追加不可テストを上から順に通しながらルールを実装していきます

tests/firestore.rules を追加して、以下のように記述してください。

テストをスタート

ファイルを追加したら、以下のコマンドを実行して、テストをスタートしてください。

テスト結果

テスト結果は、以下のようになります。(テスト結果の冒頭のみを抜粋)

「要件にあったデータの追加に成功」するテストだけが通りました

前述の通り、失敗した追加不可テストを上から順に通して行きます

リスト型データ中の指定値の有無を条件に使用する

「データ追加をリクエストしたユーザが、商品管理者でない場合は追加不可」となるよう、以下のルールを設定してください。

ここで、 request.auth.uid in request.resource.data.adminUsers の条件により、リクエストデータの商品管理者リストの中に、リクエストユーザが含まれるかをチェックしています。

リスト型のデータに、 in 演算子を使用することで、そのリストに指定の値が存在するかをチェックできます。

テスト結果

ルールの変更により、テストが再度実行され、以下のような結果が表示されます!

データの要素数の比較結果を条件に使用する

次に、「データのサイズが「9」でない場合は追加不可」となるテストを通すため、以下のようにルールを追加してください。

request.resource.data.size() == 9 の条件により、リクエストデータの要素の数が「9」である場合のみ、追加アクセスを許可しています。

マップ型やリスト型のデータには、 size() メソッドが用意されており、データの要素数を参照することができます。

テスト結果

「データのサイズが9でない場合は追加不可」となるテストが通りました。

データ型や数値の比較結果を条件に使用する

最後に、「残っているテスト」と「型と値のチェックテスト」をまとめて通してしまいます。

以下のように、ルールを調整しましょう!

ここで、 is 演算子により、各フィールドの型を指定しています。

例えば、 releaseDate フィールドは、 request.resource.data.releaseDate is timestamp の条件により、タイムスタンプ型のみが許可されています。

int 型などの数値型は、 >=< などの演算子を使って、数値の比較ができます

例えば、 request.resource.data.price >= 0 の条件によって、 price フィールドは、「0」以上でない場合はデータを追加できません。

先ほど説明した in 演算子を使って、 request.resource.data.condition in ["new","used"] の条件により、 condition フィールドの値は "new" か  "used" に制限しています。

テスト結果

全てのテストが通りました!

以上で、書籍データ追加用のルールは、実装完了です!

最後に、次のテストとの競合を避けるため、テストを終了してください。

後編へつづく!

今回の記事では、「実装目標(要件)の設定」から「データ追加ルールの実装」までを、テスト駆動のスタイルで解説してみました。

後編では、前編の内容を復習しつつ、前編と同様に、テスト駆動スタイルで Firestore 上のデータ更新と取得のルールを実装していきます。

後編はこちら

こちらの記事もオススメ!

書いた人はこんな人

広告メディア事業部
広告メディア事業部
「好きを仕事にするエンジニア集団」の(株)ライトコードです!

ライトコードは、福岡、東京、大阪の3拠点で事業展開するIT企業です。
現在は、国内を代表する大手IT企業を取引先にもち、ITシステムの受託事業が中心。
いずれも直取引で、月間PV数1億を超えるWebサービスのシステム開発・運営、インフラの構築・運用に携わっています。

システム開発依頼・お見積もり大歓迎!

また、現在「WEBエンジニア」「モバイルエンジニア」「営業」「WEBデザイナー」「WEBディレクター」を積極採用中です!
インターンや新卒採用も行っております。

以下よりご応募をお待ちしております!
https://rightcode.co.jp/recruit

関連記事

採用情報

\ あの有名サービスに参画!? /

バックエンドエンジニア

\ クリエイティブの最前線 /

フロントエンドエンジニア

\ 世界を変える…! /

Androidエンジニア

\ みんなが使うアプリを創る /

iOSエンジニア