Join us for Firebase Summit on November 10, 2021. Tune in to learn how Firebase can help you accelerate app development, release with confidence, and scale with ease. Register

リアルタイムデータベースルールの使用条件

このガイドでは、上に構築コアFirebaseセキュリティルールの言語を学ぶあなたのFirebaseリアルタイムデータベースセキュリティルールに条件を追加する方法を示すために、ガイドを。

リアルタイムデータベースセキュリティルールの主要なビルディング・ブロックが条件です。条件は、特定の操作を許可するか拒否するかを決定するブール式です。基本的なルールについては、使用してtruefalse条件としてリテラルはprefectlyうまく動作します。ただし、Realtime Database Security Rules言語を使用すると、次のようなより複雑な条件を記述できます。

  • ユーザー認証を確認する
  • 新しく送信されたデータに対して既存のデータを評価します
  • データベースのさまざまな部分にアクセスして比較する
  • 受信データを検証する
  • セキュリティロジックに着信クエリの構造を使用する

$変数を使用してパスセグメントをキャプチャする

あなたはとキャプチャ変数を宣言することによって、読み取りや書き込みのためのパスの部分をキャプチャすることができます$接頭辞。これはワイルドカードとして機能し、ルール条件内で使用するためにそのキーの値を格納します。

{
  "rules": {
    "rooms": {
      // this rule applies to any child of /rooms/, the key for each room id
      // is stored inside $room_id variable for reference
      "$room_id": {
        "topic": {
          // the room's topic can be changed if the room id has "public" in it
          ".write": "$room_id.contains('public')"
        }
      }
    }
  }
}

ダイナミック$変数も一定のパス名と並行して使用することができます。この例では、使用している$other宣言するために変数を.validateルールを確実にすることをwidget以外の子供持っていないtitlecolor 。追加の子が作成される結果となる書き込みは失敗します。

{
  "rules": {
    "widget": {
      // a widget can have a title or color attribute
      "title": { ".validate": true },
      "color": { ".validate": true },

      // but no other child paths are allowed
      // in this case, $other means any key excluding "title" and "color"
      "$other": { ".validate": false }
    }
  }
}

認証

最も一般的なセキュリティルールパターンの1つは、ユーザーの認証状態に基づいてアクセスを制御することです。たとえば、アプリでサインインしたユーザーのみにデータの書き込みを許可したい場合があります。

あなたのアプリがFirebase認証を使用する場合は、 request.auth変数は、データを要求しているクライアントの認証情報が含まれています。詳細についてはrequest.auth 、参照リファレンスドキュメントを

FirebaseAuthenticationはFirebaseRealtime Databaseと統合されており、条件を使用してユーザーごとにデータアクセスを制御できます。ユーザー認証すると、 authあなたのリアルタイムデータベースセキュリティルールルール内の変数は、ユーザーの情報が移入されます。この情報は、彼らのユニークな識別子(含まuid )ならびにそのようなFacebookのIDまたは電子メールアドレス、およびその他の情報としてリンクされたアカウントのデータを、。カスタム認証プロバイダーを実装する場合は、ユーザーの認証ペイロードに独自のフィールドを追加できます。

このセクションでは、Firebase Realtime Database SecurityRules言語をユーザーに関する認証情報と組み合わせる方法について説明します。これら2つの概念を組み合わせることで、ユーザーIDに基づいてデータへのアクセスを制御できます。

auth変数

事前に定義されたauthの認証が行われる前に、ルール内の変数はnullです。

ユーザーがで認証されるとFirebase認証には、以下の属性が含まれます:

プロバイダー使用される認証方法(「パスワード」、「匿名」、「フェイスブック」、「github」、「グーグル」、または「ツイッター」)。
uid一意のユーザーID。すべてのプロバイダーで一意であることが保証されています。
トークンFirebase AuthIDトークンの内容。リファレンスドキュメントを参照してくださいauth.token詳細については。

ここで使用する例示的ルールであるauth各ユーザのみがユーザ固有のパスに書き込むことができることを保証するために変数:

{
  "rules": {
    "users": {
      "$user_id": {
        // grants write access to the owner of this user account
        // whose uid must exactly match the key ($user_id)
        ".write": "$user_id === auth.uid"
      }
    }
  }
}

認証条件をサポートするためのデータベースの構造化

通常、ルールの作成を容易にする方法でデータベースを構造化すると便利です。リアルタイムデータベース内のユーザデータを格納するための一つの一般的なパターンは、単一ですべてのユーザーを格納することであるusers 、その子であるノードuidすべてのユーザーのための値。ログインしたユーザーだけが自分のデータを表示できるようにこのデータへのアクセスを制限したい場合、ルールは次のようになります。

{
  "rules": {
    "users": {
      "$uid": {
        ".read": "auth != null && auth.uid == $uid"
      }
    }
  }
}

認証カスタムクレームの操作

別のユーザーのためにカスタムアクセス制御を必要とするアプリケーションの場合は、Firebase認証は、開発者にすることができますFirebaseユーザーのセット主張。これらの主張は、中づけしているauth.tokenあなたのルールでの変数。ここでの使用にするルールの一例であるhasEmergencyTowelカスタム要求は:

{
  "rules": {
    "frood": {
      // A towel is about the most massively useful thing an interstellar
      // hitchhiker can have
      ".read": "auth.token.hasEmergencyTowel === true"
    }
  }
}

作成開発者は独自のカスタム認証トークンは、必要に応じてこれらのトークンへのクレームを追加することができます。これらの主張は、上のavaialbleですauth.tokenあなたのルールでの変数。

既存のデータと新しいデータ

事前に定義されたdata変数は、書き込み動作が行われる前のデータを参照するために使用されます。逆に、 newData変数は、書き込み動作が成功した場合に存在する、新しいデータが含まれています。 newData書き込まれる新しいデータと既存のデータのマージされた結果を表しています。

説明のために、このルールでは、新しいレコードを作成したり、既存のレコードを削除したりできますが、既存のnull以外のデータに変更を加えることはできません。

// we can write as long as old data or new data does not exist
// in other words, if this is a delete or a create, but not an update
".write": "!data.exists() || !newData.exists()"

他のパスのデータを参照する

ルールの基準として任意のデータを使用できます。事前に定義された変数の使い方rootdata 、およびnewData 、それが書き込みイベントの前または後に存在するであろうと、私たちは、任意のパスにアクセスすることができます。

この例を考えてみましょう、長いの値としてとして書き込み操作を可能にする/allow_writes/ノードであるtrue 、親ノードがありませんreadOnlyフラグが設定され、名前の子がありfoo新しく書き込まれたデータには:

".write": "root.child('allow_writes').val() === true &&
          !data.parent().child('readOnly').exists() &&
          newData.child('foo').exists()"

データの検証

データ構造を強制し、フォーマットして使用して行われるべきデータの内容を検証.validateた後にのみ実行されているルールを、 .writeルールは、アクセス権を付与することに成功します。以下はサンプルです.validateのみ正規表現を使用してチェックされている年間1900から2099の間の形式YYYY-MM-DD、日付を許可するルールの定義が。

".validate": "newData.isString() &&
              newData.val().matches(/^(19|20)[0-9][0-9][-\\/. ](0[1-9]|1[012])[-\\/. ](0[1-9]|[12][0-9]|3[01])$/)"

.validateルールはカスケード接続していないセキュリティルールの唯一のタイプです。子レコードで検証ルールが失敗した場合、書き込み操作全体が拒否されます。データが削除された場合また、検証の定義は(書き込まれる新しい値がある場合には、その無視されるnull )。

これらは些細なことのように思えるかもしれませんが、実際には強力なFirebase Realtime Database SecurityRuleを作成するための重要な機能です。次のルールを考慮してください。

{
  "rules": {
    // write is allowed for all paths
    ".write": true,
    "widget": {
      // a valid widget must have attributes "color" and "size"
      // allows deleting widgets (since .validate is not applied to delete rules)
      ".validate": "newData.hasChildren(['color', 'size'])",
      "size": {
        // the value of "size" must be a number between 0 and 99
        ".validate": "newData.isNumber() &&
                      newData.val() >= 0 &&
                      newData.val() <= 99"
      },
      "color": {
        // the value of "color" must exist as a key in our mythical
        // /valid_colors/ index
        ".validate": "root.child('valid_colors/' + newData.val()).exists()"
      }
    }
  }
}

このバリアントを念頭に置いて、次の書き込み操作の結果を確認してください。

JavaScript
var ref = db.ref("/widget");

// PERMISSION_DENIED: does not have children color and size
ref.set('foo');

// PERMISSION DENIED: does not have child color
ref.set({size: 22});

// PERMISSION_DENIED: size is not a number
ref.set({ size: 'foo', color: 'red' });

// SUCCESS (assuming 'blue' appears in our colors list)
ref.set({ size: 21, color: 'blue'});

// If the record already exists and has a color, this will
// succeed, otherwise it will fail since newData.hasChildren(['color', 'size'])
// will fail to validate
ref.child('size').set(99);
Objective-C
FIRDatabaseReference *ref = [[[FIRDatabase database] reference] child: @"widget"];

// PERMISSION_DENIED: does not have children color and size
[ref setValue: @"foo"];

// PERMISSION DENIED: does not have child color
[ref setValue: @{ @"size": @"foo" }];

// PERMISSION_DENIED: size is not a number
[ref setValue: @{ @"size": @"foo", @"color": @"red" }];

// SUCCESS (assuming 'blue' appears in our colors list)
[ref setValue: @{ @"size": @21, @"color": @"blue" }];

// If the record already exists and has a color, this will
// succeed, otherwise it will fail since newData.hasChildren(['color', 'size'])
// will fail to validate
[[ref child:@"size"] setValue: @99];
迅速
var ref = FIRDatabase.database().reference().child("widget")

// PERMISSION_DENIED: does not have children color and size
ref.setValue("foo")

// PERMISSION DENIED: does not have child color
ref.setValue(["size": "foo"])

// PERMISSION_DENIED: size is not a number
ref.setValue(["size": "foo", "color": "red"])

// SUCCESS (assuming 'blue' appears in our colors list)
ref.setValue(["size": 21, "color": "blue"])

// If the record already exists and has a color, this will
// succeed, otherwise it will fail since newData.hasChildren(['color', 'size'])
// will fail to validate
ref.child("size").setValue(99);
Java
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference ref = database.getReference("widget");

// PERMISSION_DENIED: does not have children color and size
ref.setValue("foo");

// PERMISSION DENIED: does not have child color
ref.child("size").setValue(22);

// PERMISSION_DENIED: size is not a number
Map<String,Object> map = new HashMap<String, Object>();
map.put("size","foo");
map.put("color","red");
ref.setValue(map);

// SUCCESS (assuming 'blue' appears in our colors list)
map = new HashMap<String, Object>();
map.put("size", 21);
map.put("color","blue");
ref.setValue(map);

// If the record already exists and has a color, this will
// succeed, otherwise it will fail since newData.hasChildren(['color', 'size'])
// will fail to validate
ref.child("size").setValue(99);
残り
# PERMISSION_DENIED: does not have children color and size
curl -X PUT -d 'foo' \
https://docs-examples.firebaseio.com/rest/securing-data/example.json

# PERMISSION DENIED: does not have child color
curl -X PUT -d '{"size": 22}' \
https://docs-examples.firebaseio.com/rest/securing-data/example.json

# PERMISSION_DENIED: size is not a number
curl -X PUT -d '{"size": "foo", "color": "red"}' \
https://docs-examples.firebaseio.com/rest/securing-data/example.json

# SUCCESS (assuming 'blue' appears in our colors list)
curl -X PUT -d '{"size": 21, "color": "blue"}' \
https://docs-examples.firebaseio.com/rest/securing-data/example.json

# If the record already exists and has a color, this will
# succeed, otherwise it will fail since newData.hasChildren(['color', 'size'])
# will fail to validate
curl -X PUT -d '99' \
https://docs-examples.firebaseio.com/rest/securing-data/example/size.json

今、同じ構造での見てみましょう、しかし、使用して.writeの代わりにルールを.validate

{
  "rules": {
    // this variant will NOT allow deleting records (since .write would be disallowed)
    "widget": {
      // a widget must have 'color' and 'size' in order to be written to this path
      ".write": "newData.hasChildren(['color', 'size'])",
      "size": {
        // the value of "size" must be a number between 0 and 99, ONLY IF WE WRITE DIRECTLY TO SIZE
        ".write": "newData.isNumber() && newData.val() >= 0 && newData.val() <= 99"
      },
      "color": {
        // the value of "color" must exist as a key in our mythical valid_colors/ index
        // BUT ONLY IF WE WRITE DIRECTLY TO COLOR
        ".write": "root.child('valid_colors/'+newData.val()).exists()"
      }
    }
  }
}

このバリアントでは、次の操作のいずれかが成功します。

JavaScript
var ref = new Firebase(URL + "/widget");

// ALLOWED? Even though size is invalid, widget has children color and size,
// so write is allowed and the .write rule under color is ignored
ref.set({size: 99999, color: 'red'});

// ALLOWED? Works even if widget does not exist, allowing us to create a widget
// which is invalid and does not have a valid color.
// (allowed by the write rule under "color")
ref.child('size').set(99);
Objective-C
Firebase *ref = [[Firebase alloc] initWithUrl:URL];

// ALLOWED? Even though size is invalid, widget has children color and size,
// so write is allowed and the .write rule under color is ignored
[ref setValue: @{ @"size": @9999, @"color": @"red" }];

// ALLOWED? Works even if widget does not exist, allowing us to create a widget
// which is invalid and does not have a valid color.
// (allowed by the write rule under "color")
[[ref childByAppendingPath:@"size"] setValue: @99];
迅速
var ref = Firebase(url:URL)

// ALLOWED? Even though size is invalid, widget has children color and size,
// so write is allowed and the .write rule under color is ignored
ref.setValue(["size": 9999, "color": "red"])

// ALLOWED? Works even if widget does not exist, allowing us to create a widget
// which is invalid and does not have a valid color.
// (allowed by the write rule under "color")
ref.childByAppendingPath("size").setValue(99)
Java
Firebase ref = new Firebase(URL + "/widget");

// ALLOWED? Even though size is invalid, widget has children color and size,
// so write is allowed and the .write rule under color is ignored
Map<String,Object> map = new HashMap<String, Object>();
map.put("size", 99999);
map.put("color", "red");
ref.setValue(map);

// ALLOWED? Works even if widget does not exist, allowing us to create a widget
// which is invalid and does not have a valid color.
// (allowed by the write rule under "color")
ref.child("size").setValue(99);
残り
# ALLOWED? Even though size is invalid, widget has children color and size,
# so write is allowed and the .write rule under color is ignored
curl -X PUT -d '{size: 99999, color: "red"}' \
https://docs-examples.firebaseio.com/rest/securing-data/example.json

# ALLOWED? Works even if widget does not exist, allowing us to create a widget
# which is invalid and does not have a valid color.
# (allowed by the write rule under "color")
curl -X PUT -d '99' \
https://docs-examples.firebaseio.com/rest/securing-data/example/size.json

これは間の違いを示し.write.validateルールを。実証されているように、これらのルールの全てを使用して書かなければならない.validateする可能除いて、 newData.hasChildren()削除を許可するかどうかに依存するルール。

クエリベースのルール

あなたがたが、フィルタとしてのルールを使用することはできません、あなたのルールでクエリパラメータを使用して、データのサブセットへのアクセスを制限することができます。使用しquery.クエリパラメータに基づいて読み取りまたは書き込みアクセスを許可するルール内の式。

たとえば、次のクエリベースのルールを使用して、ユーザーベースのセキュリティルール内のデータへのアクセスを制限すると、クエリベースのルールをbasketsアクティブユーザーが所有しているだけ買い物かごにコレクションを:

"baskets": {
  ".read": "auth.uid != null &&
            query.orderByChild == 'owner' &&
            query.equalTo == auth.uid" // restrict basket access to owner of basket
}

ルールにクエリパラメータを含む次のクエリは成功します。

db.ref("baskets").orderByChild("owner")
                 .equalTo(auth.currentUser.uid)
                 .on("value", cb)                 // Would succeed

しかし、ルールのパラメータを含まないクエリがで失敗しPermissionDeniedエラー:

db.ref("baskets").on("value", cb)                 // Would fail with PermissionDenied

クエリベースのルールを使用して、クライアントが読み取り操作を通じてダウンロードするデータの量を制限することもできます。

たとえば、次のルールは、優先度順に、クエリの最初の1000件の結果のみに読み取りアクセスを制限します。

messages: {
  ".read": "query.orderByKey &&
            query.limitToFirst <= 1000"
}

// Example queries:

db.ref("messages").on("value", cb)                // Would fail with PermissionDenied

db.ref("messages").limitToFirst(1000)
                  .on("value", cb)                // Would succeed (default order by key)

query.式は、リアルタイムデータベースセキュリティルールで使用できます。

クエリベースのルール式
表現タイプ説明
query.orderByKey
query.orderByPriority
query.orderByValue
ブール値キー、優先度、または値で並べ替えられたクエリの場合はTrue。それ以外の場合はFalse。
query.orderByChildストリング
ヌル
文字列を使用して、子ノードへの相対パスを表します。例えば、 query.orderByChild == "address/zip" 。クエリが子ノードによって順序付けられていない場合、この値はnullです。
query.startAt
query.endAt
query.equalTo
ストリング
番号
ブール値
ヌル
実行中のクエリの境界を取得します。境界セットがない場合はnullを返します。
query.limitToFirst
query.limitToLast
番号
ヌル
実行中のクエリの制限を取得するか、制限が設定されていない場合はnullを返します。

次のステップ

この条件の説明の後、ルールをより高度に理解し、次の準備が整います。

コアユースケースを処理する方法を学び、ルールを開発、テスト、および展開するためのワークフローを学びます。

リアルタイムデータベースに固有のルール機能の学習: