Na tej stronie omawiamy pojęcia z zakresu
Tworzenie struktury reguł zabezpieczeń
Pisanie warunków reguł zabezpieczeń wyjaśniających, jak
Reguły zabezpieczeń Cloud Firestore współdziałają z zapytaniami. Zwracamy uwagę na to,
na zapytania, które możesz tworzyć, i podpowiada, jak zapewnić
i zapytania korzystają z tych samych ograniczeń co reguły zabezpieczeń. Ta strona też
opisuje, jak pisać reguły zabezpieczeń, które zezwalają na zapytania na podstawie zapytań lub je odrzucają.
właściwości takich jak limit
i orderBy
.
Reguły nie są filtrami
Tworząc zapytania służące do pobierania dokumentów, pamiętaj, że reguły zabezpieczeń a nie filtry – zapytania dotyczą wszystkich albo nie mają żadnej wartości. Aby zaoszczędzić Twój czas i zasoby, Cloud Firestore ocenia zapytanie względem potencjalnego zbioru wyników zamiast rzeczywistej wartości pól dla wszystkich dokumentów. Gdyby zapytanie mogło mogą zwrócić dokumenty, których klient nie ma uprawnień do odczytu, nie powiedzie się.
Zapytania i reguły zabezpieczeń
Jak widać w poniższych przykładach, musisz napisać zapytania, aby pasowały do w Twoich regułach zabezpieczeń.
Zabezpieczanie dokumentów i wykonywanie na nich zapytań na podstawie zasad auth.uid
Poniższy przykład pokazuje, jak napisać zapytanie pobierające dokumenty
jest chroniona regułą zabezpieczeń. Załóżmy, że mamy bazę danych zawierającą zbiór
story
dokumenty:
/stories/{storyid}
{
title: "A Great Story",
content: "Once upon a time...",
author: "some_auth_id",
published: false
}
Oprócz pól title
i content
w każdym dokumencie są przechowywane
Pola author
i published
do użycia na potrzeby kontroli dostępu. W tych przykładach zakładamy,
aplikacja używa uwierzytelniania Firebase do ustawienia pola author
.
z identyfikatorem UID użytkownika, który utworzył dokument. Firebase
Uwierzytelnianie wypełnia też zmienną request.auth
w
i zasad bezpieczeństwa.
Ta reguła zabezpieczeń korzysta z request.auth
oraz
Zmienne resource.data
, które ograniczają dostęp do odczytu i zapisu dla poszczególnych
story
do autora:
service cloud.firestore {
match /databases/{database}/documents {
match /stories/{storyid} {
// Only the authenticated user who authored the document can read or write
allow read, write: if request.auth != null && request.auth.uid == resource.data.author;
}
}
}
Załóżmy, że Twoja aplikacja zawiera stronę, która wyświetla użytkownikowi listę story
stworzonych przez nich dokumentów. Możesz kierować się tymi informacjami:
za pomocą zapytania. To zapytanie zakończy się jednak niepowodzeniem, ponieważ nie jest
zawierają te same ograniczenia co w regułach zabezpieczeń:
Błąd: ograniczenia zapytania nie pasują do siebie. ograniczenia reguł zabezpieczeń
// This query will fail
db.collection("stories").get()
Zapytanie nie zostaje wykonane, nawet jeśli bieżący użytkownik jest autorem każdego
story
dokument. Dzieje się tak, ponieważ
Cloud Firestore stosuje Twoje reguły zabezpieczeń i ocenia zapytanie
w porównaniu ze zbiorem potencjalnych wyników, a nie z rzeczywistymi właściwościami funkcji
dokumentów w bazie danych. Jeśli zapytanie może potencjalnie obejmować dokumenty
które naruszają Twoje reguły zabezpieczeń, zapytanie zakończy się niepowodzeniem.
Poniższe zapytanie się sprawdza, ponieważ zawiera to samo
w polu author
jako reguły zabezpieczeń:
Prawidłowe: ograniczenia zapytań pasują do zabezpieczeń. ograniczenia reguł
var user = firebase.auth().currentUser;
db.collection("stories").where("author", "==", user.uid).get()
Zabezpieczanie dokumentów i wykonywanie na nich zapytań na podstawie pól
Aby jeszcze lepiej zademonstrować współzależność między zapytaniami a regułami, funkcja zabezpieczeń
poniższe reguły rozszerzają uprawnienia do odczytu kolekcji stories
, aby każdy użytkownik mógł
odczytywano dokumenty (story
), w których pole published
ma wartość true
.
service cloud.firestore {
match /databases/{database}/documents {
match /stories/{storyid} {
// Anyone can read a published story; only story authors can read unpublished stories
allow read: if resource.data.published == true || (request.auth != null && request.auth.uid == resource.data.author);
// Only story authors can write
allow write: if request.auth != null && request.auth.uid == resource.data.author;
}
}
}
Zapytanie o opublikowane strony musi zawierać te same ograniczenia co zabezpieczenia reguły:
db.collection("stories").where("published", "==", true).get()
Ograniczenie zapytania .where("published", "==", true)
gwarantuje, że
resource.data.published
ma wartość true
dla dowolnego wyniku. Dlatego to zapytanie
jest zgodna z regułami zabezpieczeń i może odczytywać dane.
Zapytania: OR
Podczas oceny zapytania logicznego OR
(or
, in
lub array-contains-any
)
w porównaniu z zestawem reguł, Cloud Firestore ocenia każdą wartość porównania
oddzielnie. Każda wartość porównania musi spełniać ograniczenia reguły zabezpieczeń. Dla:
na przykład w przypadku parametru
ta reguła:
match /mydocuments/{doc} {
allow read: if resource.data.x > 5;
}
Błąd: zapytanie nie gwarantuje, że:
x > 5
dla wszystkich potencjalnych dokumentów
// These queries will fail
query(db.collection("mydocuments"),
or(where("x", "==", 1),
where("x", "==", 6)
)
)
query(db.collection("mydocuments"),
where("x", "in", [1, 3, 6, 42, 99])
)
Prawidłowy: zapytanie gwarantuje, że:
x > 5
dla wszystkich potencjalnych dokumentów
query(db.collection("mydocuments"),
or(where("x", "==", 6),
where("x", "==", 42)
)
)
query(db.collection("mydocuments"),
where("x", "in", [6, 42, 99, 105, 200])
)
Ocena ograniczeń w zapytaniach
Twoje reguły zabezpieczeń mogą też akceptować lub odrzucać zapytania na podstawie swoich ograniczeń.
Zmienna request.query
zawiera te elementy: limit
, offset
,
i orderBy
właściwości zapytania. Na przykład reguły zabezpieczeń
może odrzucać zapytania, które nie ograniczają maksymalnej liczby dokumentów
pobrane do określonego zakresu:
allow list: if request.query.limit <= 10;
Poniższy zestaw reguł pokazuje, jak pisać reguły zabezpieczeń, które oceniają
na zapytania. Ten przykład powoduje rozwinięcie poprzedniego elementu stories
zestaw reguł z następującymi zmianami:
- Zestaw reguł dzieli regułę odczytu na reguły dla
get
ilist
. - Reguła
get
ogranicza pobieranie pojedynczych dokumentów do dokumentów publicznych lub dokumentów opracowanych przez użytkownika. - Reguła
list
stosuje te same ograniczenia coget
, ale do zapytań. it sprawdza limit zapytań, a następnie odrzuca zapytania bez ograniczenia lub z parametrem jest większy niż 10. - Zestaw reguł definiuje funkcję
authorOrPublished()
, która pozwala uniknąć kodu i powielaniu.
service cloud.firestore {
match /databases/{database}/documents {
match /stories/{storyid} {
// Returns `true` if the requested story is 'published'
// or the user authored the story
function authorOrPublished() {
return resource.data.published == true || request.auth.uid == resource.data.author;
}
// Deny any query not limited to 10 or fewer documents
// Anyone can query published stories
// Authors can query their unpublished stories
allow list: if request.query.limit <= 10 &&
authorOrPublished();
// Anyone can retrieve a published story
// Only a story's author can retrieve an unpublished story
allow get: if authorOrPublished();
// Only a story's author can write to a story
allow write: if request.auth.uid == resource.data.author;
}
}
}
Zapytania dotyczące grup kolekcji i reguły zabezpieczeń
Domyślnie zapytania są ograniczone do 1 kolekcji i pobierają wyniki tylko z tej kolekcji. Na zapytania dotyczące grup kolekcji, możesz pobierz wyniki z grupy kolekcji złożonej ze wszystkich kolekcji z atrybutem ten sam identyfikator. W tej sekcji dowiesz się, jak zabezpieczyć zapytania dotyczące grupy kolekcji. przy użyciu reguł zabezpieczeń.
Zabezpieczanie dokumentów i wykonywanie na nich zapytań na podstawie grup kolekcji
W regułach zabezpieczeń musisz wyraźnie zezwolić na zapytań dotyczących grupy kolekcji, tworząc regułę dla tej grupy:
- Upewnij się, że
rules_version = '2';
jest pierwszym wierszem zestawu reguł. Gromadzenie danych Zapytania grupowe wymagają parametru nowy rekurencyjny symbol wieloznaczny{name=**}
dla bezpieczeństwa reguły w wersji 2. - Napisz regułę dla grupy kolekcji za pomocą
match /{path=**}/[COLLECTION_ID]/{doc}
Weźmy na przykład forum podzielone na dokumenty forum
zawierające
posts
podkolekcji:
/forums/{forumid}/posts/{postid}
{
author: "some_auth_id",
authorname: "some_username",
content: "I just read a great story.",
}
W tej aplikacji ich właściciele mogą edytować posty, a ich użytkownicy mogą je odczytać uwierzytelnieni użytkownicy:
service cloud.firestore {
match /databases/{database}/documents {
match /forums/{forumid}/posts/{post} {
// Only authenticated users can read
allow read: if request.auth != null;
// Only the post author can write
allow write: if request.auth != null && request.auth.uid == resource.data.author;
}
}
}
Każdy uwierzytelniony użytkownik może pobierać posty z dowolnego forum:
db.collection("forums/technology/posts").get()
Co jednak w sytuacji, gdy chcesz pokazywać bieżącemu użytkownikowi jego posty na wszystkich forach?
Do pobierania za pomocą zapytania dotyczącego grupy kolekcji możesz:
wyniki ze wszystkich kolekcji (posts
):
var user = firebase.auth().currentUser;
db.collectionGroup("posts").where("author", "==", user.uid).get()
W regułach zabezpieczeń musisz zezwolić na wykonywanie tego zapytania przez
napisz regułę odczytu lub listy dla grupy kolekcji posts
:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// Authenticated users can query the posts collection group
// Applies to collection queries, collection group queries, and
// single document retrievals
match /{path=**}/posts/{post} {
allow read: if request.auth != null;
}
match /forums/{forumid}/posts/{postid} {
// Only a post's author can write to a post
allow write: if request.auth != null && request.auth.uid == resource.data.author;
}
}
}
Pamiętaj jednak, że te reguły będą dotyczyć wszystkich kolekcji o identyfikatorze posts
,
bez względu na hierarchię. Na przykład te reguły mają zastosowanie do wszystkich
posts
kolekcje:
/posts/{postid}
/forums/{forumid}/posts/{postid}
/forums/{forumid}/subforum/{subforumid}/posts/{postid}
Zabezpiecz zapytania dotyczące grup kolekcji na podstawie pola
Podobnie jak w przypadku zapytań w ramach pojedynczego zbioru zapytania dotyczące grup kolekcji muszą również spełniać
ograniczeń ustawionych przez reguły zabezpieczeń. Możemy na przykład dodać published
do każdego posta na forum, tak jak w przykładzie stories
powyżej:
/forums/{forumid}/posts/{postid}
{
author: "some_auth_id",
authorname: "some_username",
content: "I just read a great story.",
published: false
}
Możemy wtedy napisać reguły dla grupy kolekcji posts
na podstawie
Stan published
i post author
:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// Returns `true` if the requested post is 'published'
// or the user authored the post
function authorOrPublished() {
return resource.data.published == true || request.auth.uid == resource.data.author;
}
match /{path=**}/posts/{post} {
// Anyone can query published posts
// Authors can query their unpublished posts
allow list: if authorOrPublished();
// Anyone can retrieve a published post
// Authors can retrieve an unpublished post
allow get: if authorOrPublished();
}
match /forums/{forumid}/posts/{postid} {
// Only a post's author can write to a post
allow write: if request.auth.uid == resource.data.author;
}
}
}
Przy użyciu tych reguł klienty internetowe, Apple i Android mogą wykonywać te zapytania:
Każdy może pobrać opublikowane posty na forum:
db.collection("forums/technology/posts").where('published', '==', true).get()
Każdy może pobrać posty autora opublikowane na wszystkich forach:
db.collectionGroup("posts").where("author", "==", "some_auth_id").where('published', '==', true).get()
Autorzy mogą pobierać wszystkie swoje opublikowane i nieopublikowane posty ze wszystkich fora:
var user = firebase.auth().currentUser; db.collectionGroup("posts").where("author", "==", user.uid).get()
Zabezpiecz dokumenty i wyszukuj dokumenty na podstawie grupy kolekcji i ścieżki dokumentu
W niektórych przypadkach możesz chcieć ograniczyć zapytania dotyczące grup kolekcji na podstawie ścieżki do dokumentu. Aby utworzyć te ograniczenia, możesz użyć tych samych technik dla: zabezpieczanie dokumentów i wykonywanie dotyczących ich zapytań na podstawie pól.
Rozważ użycie aplikacji, która śledzi transakcje każdego użytkownika z kilku giełd i giełd kryptowalut:
/users/{identyfikator użytkownika}/Wymiana/{identyfikator-usługi}/transactions/{transaction}
{
amount: 100,
exchange: 'some_exchange_name',
timestamp: April 1, 2019 at 12:00:00 PM UTC-7,
user: "some_auth_id",
}
Zwróć uwagę na pole user
. Chociaż wiemy, do którego użytkownika transaction
należy
ze ścieżki dokumentu, duplikujemy je w każdym
transaction
, ponieważ pozwala nam robić 2 rzeczy:
Twórz zapytania dotyczące grup kolekcji ograniczone do dokumentów zawierających konkretny element
/users/{userid}
w ścieżce dokumentu. Przykład:var user = firebase.auth().currentUser; // Return current user's last five transactions across all exchanges db.collectionGroup("transactions").where("user", "==", user).orderBy('timestamp').limit(5)
Egzekwuj to ograniczenie do wszystkich zapytań w kolekcji
transactions
tak, aby jeden użytkownik nie mógł pobierać dokumentówtransaction
innego użytkownika.
To ograniczenie egzekwujemy w naszych regułach zabezpieczeń i uwzględniamy weryfikację danych
dla pola user
:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{path=**}/transactions/{transaction} {
// Authenticated users can retrieve only their own transactions
allow read: if resource.data.user == request.auth.uid;
}
match /users/{userid}/exchange/{exchangeid}/transactions/{transaction} {
// Authenticated users can write to their own transactions subcollections
// Writes must populate the user field with the correct auth id
allow write: if userid == request.auth.uid && request.data.user == request.auth.uid
}
}
}
Dalsze kroki
- Bardziej szczegółowy przykład kontroli dostępu opartej na rolach znajdziesz w artykule Ochrona danych Dostęp dla użytkowników i grup.
- Zapoznaj się z informacjami o regułach zabezpieczeń.