Poznaj podstawową składnię języka Realtime Database Rules

Reguły zabezpieczeń bazy danych czasu rzeczywistego Firebase umożliwiają kontrolę dostępu do danych przechowywanych w bazie danych. Elastyczna składnia reguł umożliwia tworzenie reguł, które pasują do wszystkiego, od wszystkich zapisów do bazy danych po operacje na poszczególnych węzłach.

Realtime Database Zasady zabezpieczeń są deklaratywne konfiguracja bazy danych. Oznacza to, że reguły są definiowane niezależnie od logiki produktu. Ma to wiele zalet: klienci nie są odpowiedzialni za egzekwowanie bezpieczeństwa, wadliwe implementacje nie narażają danych, a co najważniejsze, nie ma potrzeby pośredniczącego referenta, takiego jak serwer, aby chronić dane przed światem.

W tym temacie opisano podstawową składnię i strukturę Reguły bezpieczeństwa bazy danych czasu rzeczywistego używane do tworzenia kompletnych zestawów reguł.

Struktura zasad bezpieczeństwa

Reguły bezpieczeństwa bazy danych czasu rzeczywistego składają się z wyrażeń podobnych do JavaScript zawartych w dokumencie JSON. Struktura Twoich reguł powinna być zgodna ze strukturą danych, które przechowujesz w swojej bazie danych.

Podstawowe zasady identyfikacji zbiorem węzłów ma być zabezpieczona, metody dostępu (np odczyt, zapis) uczestniczy, oraz warunki, na podstawie których dostęp jest albo dozwolona lub zabroniona. W poniższych przykładach, nasze warunki będą proste true i false oświadczenia, ale w następnym temacie zajmiemy więcej sposobów, aby wyrazić dynamiczne warunki.

Tak więc, na przykład, jeśli staramy się zabezpieczyć child_node pod parent_node , ogólna składnia do naśladowania jest:

{
  "rules": {
    "parent_node": {
      "child_node": {
        ".read": <condition>,
        ".write": <condition>,
        ".validate": <condition>,
      }
    }
  }
}

Zastosujmy ten wzór. Załóżmy na przykład, że śledzisz listę wiadomości i masz dane, które wyglądają tak:

{
  "messages": {
    "message0": {
      "content": "Hello",
      "timestamp": 1405704370369
    },
    "message1": {
      "content": "Goodbye",
      "timestamp": 1405704395231
    },
    ...
  }
}

Twoje zasady powinny być skonstruowane w podobny sposób. Oto zestaw reguł dotyczących zabezpieczeń tylko do odczytu, które mogą mieć sens dla tej struktury danych. Ten przykład ilustruje, w jaki sposób określamy węzły bazy danych, do których mają zastosowanie reguły, oraz warunki oceny reguł w tych węzłach.

{
  "rules": {
    // For requests to access the 'messages' node...
    "messages": {
      // ...and the individual wildcarded 'message' nodes beneath
      // (we'll cover wildcarding variables more a bit later)....
      "$message": {

        // For each message, allow a read operation if <condition>. In this
        // case, we specify our condition as "true", so read access is always granted.
        ".read": "true",

        // For read-only behavior, we specify that for write operations, our
        // condition is false.
        ".write": "false"
      }
    }
  }
}

Podstawowe zasady działania

Istnieją trzy typy reguł zapewniającą pełne bezpieczeństwo w oparciu o rodzaju wykonywanej operacji na danych: .write , .read i .validate . Oto krótkie podsumowanie ich celów:

Typy reguł
.czytać Opisuje, czy i kiedy użytkownicy mogą odczytywać dane.
.pisać Opisuje, czy i kiedy można zapisywać dane.
.uprawomocnić Definiuje, jak będzie wyglądać poprawnie sformatowana wartość, czy ma atrybuty podrzędne i typ danych.

Zmienne przechwytywania symboli wieloznacznych

Wszystkie instrukcje reguł wskazują na węzły. Oświadczenie może wskazywać na konkretnego węzła lub użyć $ wieloznacznych zmienne przechwytywania do punktu do grup węzłów na poziomie hierarchii. Użyj tych zmiennych przechwytywania do przechowywania wartości kluczy węzłów do użycia w kolejnych instrukcjach reguł. Technika ta pozwala pisać bardziej złożonych warunków regulaminu, coś omówimy bardziej szczegółowo w następnym temacie.

{
  "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')"
        }
      }
    }
  }
}

Te dynamiczne $ zmienne mogą być również wykorzystywane równolegle ze stałych nazw ścieżek. W tym przykładzie używamy $other zmienną zadeklarować .validate regułę, która zapewnia, że widget ma dzieci innych niż title i color . Każdy zapis, który skutkowałby utworzeniem dodatkowych dzieci, zakończyłby się niepowodzeniem.

{
  "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 }
    }
  }
}

Kaskadowe zasady odczytu i zapisu

.read i .write zasady pracy z top-down, z nadrzędnych zasad płytszych głębszych zasad. Jeżeli dotacje reguła odczytu lub zapisu uprawnień w danej ścieżce, to również daje dostęp do wszystkich węzłów potomnych pod nią. Rozważ następującą strukturę:

{
  "rules": {
     "foo": {
        // allows read to /foo/*
        ".read": "data.child('baz').val() === true",
        "bar": {
          /* ignored, since read was allowed already */
          ".read": false
        }
     }
  }
}

Taka struktura pozwala na zabezpieczenie /bar/ należy czytać od ilekroć /foo/ zawiera dziecięcą baz o wartości true . ".read": false reguła pod /foo/bar/ nie ma znaczenia tutaj, ponieważ dostęp nie może być odwołane przez ścieżkę dziecięcej.

Choć może nie wydawać się to od razu intuicyjne, jest to potężna część języka reguł i pozwala na implementację bardzo złożonych uprawnień dostępu przy minimalnym wysiłku. Zostanie to zilustrowane, gdy przejdziemy do bezpieczeństwa opartego na użytkownikach w dalszej części tego przewodnika.

Zauważ, że .validate przepisy nie kaskadowo. Aby zapis był dozwolony, wszystkie reguły walidacji muszą być spełnione na wszystkich poziomach hierarchii.

Reguły nie są filtrami

Reguły są stosowane w sposób atomowy. Oznacza to, że operacja odczytu lub zapisu kończy się niepowodzeniem natychmiast, jeśli w tej lokalizacji lub w lokalizacji nadrzędnej nie ma reguły, która udziela dostępu. Nawet jeśli każda ścieżka podrzędna, której dotyczy problem, jest dostępna, odczyt w lokalizacji nadrzędnej całkowicie się nie powiedzie. Rozważ tę strukturę:

{
  "rules": {
    "records": {
      "rec1": {
        ".read": true
      },
      "rec2": {
        ".read": false
      }
    }
  }
}

Bez zrozumienia, że reguły są oceniane atomowo, to może wydawać się pobierania /records/ ścieżkę wróci rec1 ale nie rec2 . Rzeczywisty wynik jest jednak błędem:

JavaScript
var db = firebase.database();
db.ref("records").once("value", function(snap) {
  // success method is not called
}, function(err) {
  // error callback triggered with PERMISSION_DENIED
});
Cel C
FIRDatabaseReference *ref = [[FIRDatabase database] reference];
[[_ref child:@"records"] observeSingleEventOfType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  // success block is not called
} withCancelBlock:^(NSError * _Nonnull error) {
  // cancel block triggered with PERMISSION_DENIED
}];
Szybki
var ref = FIRDatabase.database().reference()
ref.child("records").observeSingleEventOfType(.Value, withBlock: { snapshot in
    // success block is not called
}, withCancelBlock: { error in
    // cancel block triggered with PERMISSION_DENIED
})
Jawa
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference ref = database.getReference("records");
ref.addListenerForSingleValueEvent(new ValueEventListener() {
  @Override
  public void onDataChange(DataSnapshot snapshot) {
    // success method is not called
  }

  @Override
  public void onCancelled(FirebaseError firebaseError) {
    // error callback triggered with PERMISSION_DENIED
  });
});
RESZTA
curl https://docs-examples.firebaseio.com/rest/records/
# response returns a PERMISSION_DENIED error

Od operacji odczytu w /records/ jest atomowy, a nie ma reguła odczytu że dotacje dostęp do wszystkich danych wynikających /records/ , to rzuci PERMISSION_DENIED błąd. Jeśli zastosujemy tę zasadę w symulatorze bezpieczeństwa w naszej konsoli Firebase , widzimy, że operacja odczytu została odrzucona, ponieważ żaden przepis odczytu wstępu do /records/ ścieżki. Jednak należy pamiętać, że zasada rec1 nigdy nie została oceniona, ponieważ nie było na ścieżce poprosiliśmy. Aby sprowadzić rec1 , musielibyśmy uzyskać do niego dostęp bezpośrednio:

JavaScript
var db = firebase.database();
db.ref("records/rec1").once("value", function(snap) {
  // SUCCESS!
}, function(err) {
  // error callback is not called
});
Cel C
FIRDatabaseReference *ref = [[FIRDatabase database] reference];
[[ref child:@"records/rec1"] observeSingleEventOfType:FEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
    // SUCCESS!
}];
Szybki
var ref = FIRDatabase.database().reference()
ref.child("records/rec1").observeSingleEventOfType(.Value, withBlock: { snapshot in
    // SUCCESS!
})
Jawa
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference ref = database.getReference("records/rec1");
ref.addListenerForSingleValueEvent(new ValueEventListener() {
  @Override
  public void onDataChange(DataSnapshot snapshot) {
    // SUCCESS!
  }

  @Override
  public void onCancelled(FirebaseError firebaseError) {
    // error callback is not called
  }
});
RESZTA
curl https://docs-examples.firebaseio.com/rest/records/rec1
# SUCCESS!

Nakładające się oświadczenia

Istnieje możliwość zastosowania więcej niż jednej reguły do ​​węzła. W przypadku, gdy wiele reguł wyrażenia identyfikacji węzła, metoda dostęp jest zabroniony, jeżeli którykolwiek z warunków jest false :

{
  "rules": {
    "messages": {
      // A rule expression that applies to all nodes in the 'messages' node
      "$message": {
        ".read": "true",
        ".write": "true"
      },
      // A second rule expression applying specifically to the 'message1` node
      "message1": {
        ".read": "false",
        ".write": "false"
      }
    }
  }
}

W powyższym przykładzie, odczytuje do message1 węźle zostaną odrzucone, ponieważ drugi reguły zawsze jest false , chociaż pierwsza zasada jest zawsze true .

Następne kroki

Możesz pogłębić swoją wiedzę na temat reguł zabezpieczeń bazy danych czasu rzeczywistego Firebase:

  • Dowiedz się kolejną ważną koncepcję języka reguł, dynamicznych warunkach , które pozwalają reguły wyboru autoryzacji użytkownika, porównać istniejące i przychodzących danych, sprawdzania poprawności danych przychodzących, należy sprawdzić strukturę zapytań pochodzących od klienta i wiele innych.

  • Przeglądu typowych przypadków użycia bezpieczeństwa i definicje Firebase zasad bezpieczeństwa, że ich rozwiązania .