1. HOME
  2. ブログ
  3. IT技術
  4. テスト駆動で学ぶ Firestore セキュリティルール【カスタム関数編:第2回】

テスト駆動で学ぶ Firestore セキュリティルール【カスタム関数編:第2回】

【第2回】テスト駆動で成績データコレクションのルールを実装する

前回は、カスタム関数について簡単に解説した後、「カスタム関数編」で扱う成績コレクション records の要件を設定し、ルール実装に使用するテスト環境とテストデータを準備しました。

今回は、前回設定した要件に沿って、データ追加ルールの実装を進めていきます

前回の記事はこちら

前回の記事は、以下をご参照ください。

Firestore 上のデータ追加ルールの実装について

テストの作成

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

  1. admin ユーザ以外は追加不可
  2. 成績フィールドは空のマップ
  3. 所定のフォーマットでないデータは追加不可

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

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

テストのコード

テストの概要

各テストで共通の内容

前準備で用意した InitialData クラスを使い、 beforeEach() 内で users コレクションの初期データを用意しています。

またテスト毎に、テスト対象となるロールを持ったユーザで認証された クライアントを取得しています。

「成績フィールドは空のマップ」であるテスト

テストの内容に沿って、データ追加の前に、リクエストデータの成績フィールドへ空のマップ以外の値を設定しています。

「所定のフォーマットでないデータは追加不可」となるテスト

情報が不足したデータと、不正な型をもつデータを用意し、データの追加チェックを実行。

情報が不足しているデータとして、任意のフィールドを削除したデータを作成しています。

また、不正な型をもつデータとして、任意のフィールドに null を設定したデータを用意しました。

Firestore 上のデータ追加ルールを実装してみる

それでは、作成したテストに沿って、セキュリティルールを実装していきましょう。

全ての create アクセスを許可するルールを設定

まずは、 students/{studentId}/records パスの create アクセスを全て許可し、「要件にあったデータの追加に成功」するテストを通したところからスタートします。

その後、失敗した残りのテストを、上から順に通して行きたいと思います。

tests/firestore.rules ファイルを追加して、以下のようにルールを設定してください。

テストをスタート

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

テスト結果

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

期待した通りに、 要件にあったデータの追加に成功 するテストが通ったので、失敗しているテストを順次、上から通して行きます。

認証をチェックする項目をルールに追加

ログインしていないユーザは追加不可 となるように、セキュリティルールに認証をチェックする項目を追加します。

セキュリティルールを、以下のように調整してください。

テスト結果

テスト結果は、以下の通りとなります。

ここで、 request.auth.uid != null により、ログイン状態をチェックしています。

ですが、このままだと少しわかりにくく、ルールが複雑になってきたときに見通しが悪そうです。

ログインチェック用のカスタム関数を定義

ログイン状態の確認はこの後、何度も出てくる内容なので、ログインチェック用の関数を定義して、再利用可能な状態に整理しておきます。

以下のように、セキュリティルールを調整してください。

ここで、ログインチェック関数として isLoggedIn() を定義しています。

isLoggedIn() 内で request 変数を使用しているように、カスタム関数内でも  request 変数や resource 変数を利用することができます

カスタム関数を使って、許可条件に名前付けしたことで、ルールの見通しがよくなりました。

ルールの変更が、テスト結果に影響していないか確認しておきます。

テスト結果

テスト結果は、以下の通りです。

テスト結果に変化はないので、問題なくルールを整理することができました。

「成績フィールドは空のマップ」となるようにルールを設定

続けて、 成績フィールドは空のマップ となるようにルールを調整します。

以下のように、ルールを調整してください。

request.resource.data.record == {} の条件により、リクエストデータの成績フィールドが、空マップであることをチェックしています。

テスト結果

テスト結果は、以下の通りです。

カスタム関数でルールを整理

ログインチェックの場合と同様に、ルールの見通しをよくするため、カスタム関数を使ってルールを整理します。

以下のように、ルールを調整してください。

成績フィールドが、空マップであるかをチェックする関数として isRecordEmpty() を定義しました。

カスタム関数には、引数を利用することができます

isRecordEmpty() 関数は、チェック対象の resoruce を引数で指定するように定義。

そのため、リクエストデータ、データベース上のデータの双方のチェックに利用することができます。

テスト結果

テスト結果は、以下の通りとなります。

テスト結果に変化はないので、ルールの調整に問題はなさそうです。

「所定のフォーマットでないデータは追加不可」となるルールを設定

続いて、 所定のフォーマットでないデータは追加不可 となるようにルールを調整します。

以下のように、ルールを調整してください。

フォーマットチェック用の関数 isValidFormat() を定義し、フォーマットチェックを全て isValidFormat() 関数内で行っています。

先ほどのルールでは、「allow式」にフォーマットチェックの条件を、そのまま記述していました。

そのため、条件設定の記述がだらだらと長くなってしまっていて、ルールの全体がわかりにくなっていました。

カスタム関数を使って、フォーマットチェックを1つにまとめたことで、「allow式」の内容がスッキリしてわかりやすくなりました。

解説の簡素化のため、今回は最初から、カスタム関数を使ってルールを整理・調整しています。
ですが、実際のルールの実装では、ここまでの実装の流れと同様、「エラー→とりあえずテストを通す→リファクタリング(カスタム関数利用など)」という流れで実装を進めるのがおすすめです。

テスト結果

テスト結果は、以下の通りとなります。

所定のフォーマットでないデータは追加不可 となるテストが通りました。

「admin ユーザ以外は追加不可」となるルールを設定

続いては、 adminユーザ以外は追加不可 となるテストを通します。

以下のように、ルールを調整してください。

カスタム関数 isAdmin() を定義して、「allow式」の条件中で  isLoggedIn() 関数を呼び出していた部分を、  isAdmin() に変更しました。

ログインチェックは、 isAdmin() 内に移しています。

isAdmin() 内で使用している  get() 関数数は、データベース上の別のコレクションのデータを参照する関数です。

get() 関数で指定するパス名に変数を使用する場合は、上記のルールで使用しているように、 $(変数名) と記述する必要があります。

isAdmin() 関数の場合は、 users コレクションのリクエストユーザのデータを参照しています。

認証されたユーザで、かつリクエストユーザのロール情報に admin が含まれる場合に  true が返されます。

テスト結果

テスト結果は、以下の通りとなります。

全てのテストが成功し、要件に沿ったデータ追加ルールが実装できました

せっかくのテスト環境なので、カスタム関数を使って、もう少しだけルールを整理・調整したいと思います。

次回以降のデータ更新ルールや取得ルールの実装で、teacher ユーザや student ユーザの判定が必要となります。

カスタム関数 isAdmin() を汎用化

isAdmin() の中身を少し調整して、汎用化しておきます。

以下のように、ルールを調整してください。

ユーザロールのチェック用に関数 isUserRole() を定義しました

isUserRole() 関数は、引数にロールを指定することで、対象のロールを持ったユーザかどうかを判定します。

関数 isAdmin() 内では、 isUserRole() 関数の引数に  admin ロールを指定して admin ユーザかどうかを判定しています。

同様に、引数に teacher ロールを指定すれば teacher ユーザであるかどうかを判定することができます。

テスト結果

テスト結果は、以下の通りです。

テスト結果に変化はないので、問題なくルールを調整することができました。

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

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

第3回へつづく!

「カスタム関数編」第2回となるこの記事では、カスタム関数を取り入れつつ、成績コレクション records へのデータ追加用のセキュリティルールを実装してみました。

次回は、成績コレクション records のデータ更新用セキュリティルールの実装を進めていきます。

ぜひ、ご覧ください!

第3回の記事はこちら

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

書いた人はこんな人

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

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

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

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

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

関連記事

採用情報

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

バックエンドエンジニア

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

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

\ 世界を変える…! /

Androidエンジニア

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

iOSエンジニア