Reguły zabezpieczeń Bazy danych czasu rzeczywistego Firebase pozwalają kontrolować dostęp do danych przechowywanych w swojej bazie danych. Elastyczna składnia reguł umożliwia reguły, które pasują do wszystkiego, od wszystkich zapisów do bazy danych po operacje w poszczególnych węzłach.
Reguły zabezpieczeń bazy danych czasu rzeczywistego to konfiguracja deklaratywna bazy danych. Oznacza to, że że reguły są zdefiniowane niezależnie od logiki usługi. Ten Ma wiele zalet: klienci nie są odpowiedzialni za bezpieczeństwo, nie zaszkodzą Twoim danym i, co najważniejsze, nie potrzeba pośrednika, np. serwera, do ochrony danych z całego świata.
W tym temacie opisano podstawową składnię i strukturę reguł zabezpieczeń Bazy danych czasu rzeczywistego służy do tworzenia kompletnych zestawów reguł.
Tworzenie struktury reguł zabezpieczeń
Reguły zabezpieczeń bazy danych czasu rzeczywistego składają się z wyrażeń podobnych do JavaScriptu zawartych w Dokument JSON. Struktura reguł powinna być taka sama jak przechowywane w bazie danych.
Reguły podstawowe określają zbiór węzłów, które mają zostać zabezpieczone, metody dostępu (np. odczyt,
zapisu), a także warunki, w których przypadku dostęp jest dozwolony lub zabroniony.
W poniższych przykładach nasze warunki będą proste: true
oraz
false
. jednak w następnym temacie omówimy bardziej dynamiczne sposoby
wyraźne warunki.
Jeśli na przykład próbujemy zabezpieczyć child_node
na podstawie parent_node
,
ogólna składnia to:
{ "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 mają dane podobne do tych:
{ "messages": { "message0": { "content": "Hello", "timestamp": 1405704370369 }, "message1": { "content": "Goodbye", "timestamp": 1405704395231 }, ... } }
Struktura reguł powinna wyglądać podobnie. Oto zestaw zabezpieczeń tylko do odczytu, które mogą mieć sens w przypadku tej struktury danych. Ten Pokazujemy na przykład, jak 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" } } } }
Operacje na regułach podstawowych
Istnieją 3 typy reguł egzekwowania bezpieczeństwa w zależności od typu
wykonywanie operacji na danych: .write
, .read
i .validate
. Tutaj
Oto krótkie podsumowanie ich przeznaczenia:
Typy reguł | |
---|---|
.read, | Określa, czy i kiedy użytkownicy mogą odczytywać dane. |
.write, | Określa, czy i kiedy można zapisywać dane. |
.validate, | Określa, jak będzie wyglądać prawidłowo sformatowana wartość atrybut podrzędny oraz typ danych. |
Zmienne przechwytywania symboli wieloznacznych
Wszystkie instrukcje reguł wskazują na węzły. Wyrażenie może wskazywać
lub użyj symbolu wieloznacznego $
, aby przechwytywać zmienne w celu wskazania zbiorów węzłów
danego poziomu. Użyj tych zmiennych przechwytywania, aby przechowywać wartość węzła
do użytku w kolejnych instrukcjach reguł. Ta technika pozwala pisać
bardziej złożonychRules warunków, które 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')" } } } } }
Dynamicznych zmiennych $
można też używać równolegle ze stałą ścieżką.
nazw. W tym przykładzie używamy zmiennej $other
do deklarowania
regułę .validate
, która zapewnia,
widget
nie ma elementów potomnych innych niż title
i color
.
Każdy zapis, który spowodowałby utworzenie dodatkowych elementów podrzędnych, kończy 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 } } } }
Kaskada reguł odczytu i zapisu
Reguły .read
i .write
działają od góry, ale niżej
i zastępują reguły bardziej zaawansowane. Jeśli reguła przyznaje uprawnienia do odczytu lub zapisu w określonym
, a potem daje również dostęp do
wszystkich podrzędnych węzłów. Weź pod uwagę taką strukturę:
{ "rules": { "foo": { // allows read to /foo/* ".read": "data.child('baz').val() === true", "bar": { /* ignored, since read was allowed already */ ".read": false } } } }
Ta struktura zabezpieczeń umożliwia odczyt z /bar/
w dowolnym momencie
/foo/
zawiera element podrzędny baz
o wartości true
.
Reguła ".read": false
w regule /foo/bar/
nie ma
ponieważ dostęp nie może zostać unieważniony przez ścieżkę podrzędną.
Choć może się to nie wydawać od razu intuicyjne, to bardzo ważna część języka reguł i umożliwia wdrożenie bardzo złożonych uprawnień dostępu przy minimalnym nakładzie pracy. Ten zabezpieczeń opartych na użytkownikach w dalszej części tego przewodnika.
Pamiętaj, że reguły .validate
nie są kaskadowe. Wszystkie reguły weryfikacji
musi być spełniony na wszystkich poziomach hierarchii, aby możliwy był zapis.
Reguły nie są filtrami
Reguły są stosowane szczegółowo. Oznacza to, że odczyt lub zapis operacja kończy się niepowodzeniem natychmiast, jeśli w tej lokalizacji lub w lokalizacja nadrzędna, która przyznaje dostęp. Nawet jeśli każda ścieżka podrzędna, której dotyczy problem, jest dostępna, w lokalizacji nadrzędnej nie uda się całkowicie. Weźmy pod uwagę tę strukturę:
{ "rules": { "records": { "rec1": { ".read": true }, "rec2": { ".read": false } } } }
Może się wydawać, że bez zrozumienia reguł
np. pobieranie ścieżki /records/
zwró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 });
Objective-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 }];
Swift
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 })
Java
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 }); });
REST
curl https://docs-examples.firebaseio.com/rest/records/ # response returns a PERMISSION_DENIED error
Operacja odczytu w /records/
jest niepodzielna i nie ma
odczytują regułę, która przyznaje dostęp do wszystkich danych w jednostce organizacyjnej /records/
,
spowoduje to błąd PERMISSION_DENIED
. Jeśli ocenimy
w symulatorze zabezpieczeń w konsoli Firebase, widzimy, że
odmowa odczytu, ponieważ żadna reguła odczytu nie zezwala na dostęp
Ścieżka /records/
. Pamiętaj jednak, że reguła dla rec1
nie została nigdy oceniona, ponieważ nie znajdowała się na żądanej ścieżce. Do pobrania
rec1
, musimy uzyskać do niego bezpośredni dostęp:
JavaScript
var db = firebase.database(); db.ref("records/rec1").once("value", function(snap) { // SUCCESS! }, function(err) { // error callback is not called });
Objective-C
FIRDatabaseReference *ref = [[FIRDatabase database] reference]; [[ref child:@"records/rec1"] observeSingleEventOfType:FEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) { // SUCCESS! }];
Swift
var ref = FIRDatabase.database().reference() ref.child("records/rec1").observeSingleEventOfType(.Value, withBlock: { snapshot in // SUCCESS! })
Java
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 } });
REST
curl https://docs-examples.firebaseio.com/rest/records/rec1 # SUCCESS!
Nakładające się oświadczenia
Do węzła może być stosowana więcej niż 1 reguła. W
jeśli wiele wyrażeń reguł identyfikuje węzeł, metoda dostępu to
odmowa, jeśli 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 odczyty do węzła message1
będą
odrzucona, ponieważ druga reguła ma zawsze wartość false
, mimo że pierwsza
ma zawsze wartość true
.
Dalsze kroki
Możesz lepiej zrozumieć reguły zabezpieczeń Bazy danych czasu rzeczywistego Firebase:
Poznaj kolejną główną pojęcie języka Rules – dynamiczny. warunki, dzięki którym Rules może sprawdzić użytkownika autoryzacja, porównywanie istniejących i przychodzących danych, weryfikowanie danych przychodzących, sprawdzanie strukturę zapytań pochodzących od klienta itd.
Przejrzyj typowe przypadki użycia zabezpieczeń i odpowiadające im definicje reguł zabezpieczeń Firebase.