Ten przewodnik jest rozszerzeniem przewodnika dotyczącego podstawowej składni języka Firebase Security Rules Pokazuje, jak dodawać warunki do Firebase Security Rules dla Cloud Storage.
Podstawowym elementem składowym Cloud Storage Security Rules jest warunek. Warunek to wyrażenie logiczne, które określa, czy dana operacja powinna być dozwolona czy zabroniona. W przypadku podstawowych reguł używanie literałów true i false jako warunków sprawdza się doskonale. Język Firebase Security Rules dla Cloud Storage
umożliwia pisanie bardziej złożonych warunków, które mogą:
- sprawdzać uwierzytelnianie użytkowników,
- weryfikować przychodzące dane.
Uwierzytelnianie
Firebase Security Rules dla Cloud Storage są zintegrowane z Firebase Authentication, aby zapewnić zaawansowane uwierzytelnianie użytkowników w Cloud Storage. Umożliwia to precyzyjną kontrolę dostępu na podstawie deklaracji tokena Firebase Authentication.
Gdy uwierzytelniony użytkownik wysyła żądanie do Cloud Storage,
zmienna request.auth jest wypełniana uid
(request.auth.uid) użytkownika oraz deklaracjami tokena JWT Firebase Authentication
(request.auth.token).
Dodatkowo, gdy używasz uwierzytelniania niestandardowego, dodatkowe deklaracje są widoczne w polu request.auth.token.
Gdy żądanie wysyła nieuwierzytelniony użytkownik, zmienna request.auth ma wartość null.
Na podstawie tych danych można zabezpieczać pliki na kilka typowych sposobów:
- Publiczne: ignoruj
request.auth. - Prywatne z uwierzytelnianiem: sprawdź, czy
request.authnie ma wartościnull. - Prywatne dla użytkownika: sprawdź, czy
request.auth.uidjest równeuidścieżki. - Prywatne dla grupy: sprawdź deklaracje tokena niestandardowego, aby dopasować je do wybranej deklaracji, lub odczytaj metadane pliku, aby sprawdzić, czy istnieje pole metadanych.
Publiczne
Każda reguła, która nie uwzględnia kontekstu request.auth, może być uznawana za
public regułę, ponieważ nie uwzględnia kontekstu uwierzytelniania użytkownika.
Te reguły mogą być przydatne do udostępniania danych publicznych, takich jak zasoby gry, pliki dźwiękowe lub inne treści statyczne.
// Anyone to read a public image if the file is less than 100kB // Anyone can upload a public file ending in '.txt' match /public/{imageId} { allow read: if resource.size < 100 * 1024; allow write: if imageId.matches(".*\\.txt"); }
Prywatne z uwierzytelnianiem
W niektórych przypadkach możesz chcieć, aby dane były widoczne dla wszystkich uwierzytelnionych użytkowników aplikacji, ale nie dla użytkowników nieuwierzytelnionych. Ponieważ zmienna request.auth ma wartość null dla wszystkich nieuwierzytelnionych użytkowników, wystarczy sprawdzić, czy zmienna request.auth istnieje, aby wymagać uwierzytelnienia:
// Require authentication on all internal image reads match /internal/{imageId} { allow read: if request.auth != null; }
Prywatne dla użytkownika
Najczęstszym przypadkiem użycia request.auth jest przyznawanie poszczególnym użytkownikom szczegółowych uprawnień do ich plików: od przesyłania zdjęć profilowych po odczytywanie dokumentów prywatnych.
Ponieważ pliki w Cloud Storage mają pełną "ścieżkę" do pliku, wystarczy, aby plik był kontrolowany przez użytkownika, jeśli w prefiksie nazwy pliku znajduje się unikalna informacja identyfikująca użytkownika (np. uid użytkownika), którą można sprawdzić podczas oceny reguły:
// Only a user can upload their profile picture, but anyone can view it match /users/{userId}/profilePicture.png { allow read; allow write: if request.auth.uid == userId; }
Prywatne dla grupy
Innym równie częstym przypadkiem użycia jest zezwalanie na uprawnienia grupowe do obiektu, np. umożliwianie kilku członkom zespołu współpracy nad udostępnionym dokumentem. Można to zrobić na kilka sposobów:
- Wygeneruj Firebase Authentication token niestandardowy który zawiera dodatkowe informacje o członku grupy (np. identyfikator grupy).
- Dołącz informacje o grupie (np. identyfikator grupy lub listę autoryzowanych
uids) do metadanych pliku
Gdy te dane są przechowywane w tokenie lub metadanych pliku, można się do nich odwoływać w regule:
// Allow reads if the group ID in your token matches the file metadata's `owner` property // Allow writes if the group ID is in the user's custom token match /files/{groupId}/{fileName} { allow read: if resource.metadata.owner == request.auth.token.groupId; allow write: if request.auth.token.groupId == groupId; }
Ocena żądania
Przesyłanie, pobieranie, zmiany metadanych i usuwanie są oceniane za pomocą
request wysyłanego do Cloud Storage. Oprócz unikalnego identyfikatora użytkownika i
ładunku Firebase Authentication w obiekcie request.auth (jak opisano powyżej)
zmienna request zawiera ścieżkę pliku, w którym jest wykonywane
żądanie, czas otrzymania żądania oraz nową wartość resource
jeśli żądanie jest zapisem.
Obiekt request zawiera też unikalny identyfikator użytkownika i
Firebase Authentication ładunek w obiekcie request.auth, co zostanie
dokładniej wyjaśnione w sekcji zabezpieczeń opartych na użytkownikach
w dokumentacji.
Pełną listę właściwości obiektu request znajdziesz poniżej:
| Właściwość | Typ | Opis |
|---|---|---|
auth |
map<string, string> | Gdy użytkownik jest zalogowany, udostępnia uid, unikalny identyfikator użytkownika, oraz
token, mapę deklaracji tokena JWT Firebase Authentication. W przeciwnym razie będzie mieć wartość
null. |
params |
map<string, string> | Mapa zawierająca parametry zapytania żądania. |
path |
path | A path reprezentująca ścieżkę, w której jest wykonywane żądanie. |
resource |
map<string, string> | Nowa wartość zasobu, dostępna tylko w żądaniach write.
|
time |
timestamp | Sygnatura czasowa reprezentująca czas serwera, w którym jest oceniane żądanie. |
Ocena zasobów
Podczas oceniania reguł możesz też oceniać metadane przesyłanego, pobieranego, modyfikowanego lub usuwanego pliku. Umożliwia to tworzenie złożonych i zaawansowanych reguł, które np. zezwalają na przesyłanie tylko plików o określonych typach treści lub usuwanie tylko plików o określonym rozmiarze.
Firebase Security Rules dla Cloud Storage udostępnia metadane pliku w obiekcie resource, który zawiera pary klucz/wartość metadanych widoczne w obiekcie
Cloud Storage. Te właściwości można sprawdzać w żądaniach read lub write, aby zapewnić integralność danych.
W przypadku żądań write (takich jak przesyłanie, aktualizowanie metadanych i usuwanie) oprócz obiektu resource, który zawiera metadane pliku znajdującego się obecnie w ścieżce żądania, możesz też używać obiektu request.resource, który zawiera podzbiór metadanych pliku, które mają zostać zapisane, jeśli zapis jest dozwolony. Możesz używać tych 2 wartości, aby zapewnić integralność danych lub wymusić ograniczenia aplikacji, takie jak typ lub rozmiar pliku.
Pełną listę właściwości obiektu resource znajdziesz poniżej:
| Właściwość | Typ | Opis |
|---|---|---|
name |
string | Pełna nazwa obiektu. |
bucket |
string | Nazwa zasobnika, w którym znajduje się ten obiekt. |
generation |
int | Generacja obiektu Google Cloud Storage obiektu. |
metageneration |
int | Metageneracja obiektu Google Cloud Storage. |
size |
int | Rozmiar obiektu w bajtach. |
timeCreated |
timestamp | Sygnatura czasowa reprezentująca czas utworzenia obiektu. |
updated |
timestamp | Sygnatura czasowa reprezentująca czas ostatniej aktualizacji obiektu. |
md5Hash |
string | Skrót MD5 obiektu. |
crc32c |
string | Skrót crc32c obiektu. |
etag |
string | Tag etag powiązany z tym obiektem. |
contentDisposition |
string | Dyspozycja treści powiązana z tym obiektem. |
contentEncoding |
string | Kodowanie treści powiązane z tym obiektem. |
contentLanguage |
string | Język treści powiązany z tym obiektem. |
contentType |
string | Typ treści powiązany z tym obiektem. |
metadata |
map<string, string> | Pary klucz/wartość dodatkowych metadanych niestandardowych określonych przez dewelopera. |
request.resource zawiera wszystkie te elementy z wyjątkiem generation,
metageneration, etag, timeCreated i updated.
Ulepszanie za pomocą Cloud Firestore
Aby ocenić inne kryteria autoryzacji, możesz uzyskać dostęp do dokumentów w Cloud Firestore.
Za pomocą funkcji firestore.get() i firestore.exists() reguły bezpieczeństwa
mogą oceniać przychodzące żądania w porównaniu z dokumentami w Cloud Firestore.
Funkcje firestore.get() i firestore.exists() oczekują w pełni określonych ścieżek dokumentów. Gdy używasz zmiennych do tworzenia ścieżek dla firestore.get() i firestore.exists(), musisz jawnie wskazać zmianę znaczenia zmiennych za pomocą składni $(variable).
W przykładzie poniżej widzimy regułę, która ogranicza dostęp do odczytu plików do tych użytkowników, którzy są członkami określonych klubów.
service firebase.storage {
match /b/{bucket}/o {
match /users/{club}/files/{fileId} {
allow read: if club in
firestore.get(/databases/(default)/documents/users/$(request.auth.id)).data.memberships
}
}
}service firebase.storage {
match /b/{bucket}/o {
match /users/{userId}/photos/{fileId} {
allow read: if
firestore.exists(/databases/(default)/documents/users/$(userId)/friends/$(request.auth.id))
}
}
}Gdy utworzysz i zapiszesz pierwsze Cloud Storage Security Rules, które używają tych Cloud Firestore funkcji, w konsoli Firebase lub interfejsie wiersza poleceń Firebase pojawi się prośba o włączenie uprawnień do połączenia tych 2 usług.
Możesz wyłączyć tę funkcję, usuwając rolę IAM, jak opisano w Zarządzanie regułami bezpieczeństwa Firebase i ich wdrażanieFirebase Security Rules.
Sprawdzanie danych
Firebase Security Rules dla Cloud Storage mogą też służyć do sprawdzania danych, w tym
nazwy i ścieżki pliku oraz właściwości metadanych pliku, takich jak
contentType i size.
service firebase.storage { match /b/{bucket}/o { match /images/{imageId} { // Only allow uploads of any image file that's less than 5MB allow write: if request.resource.size < 5 * 1024 * 1024 && request.resource.contentType.matches('image/.*'); } } }
Funkcje niestandardowe
Gdy Twoje Firebase Security Rules stają się bardziej złożone, możesz chcieć umieścić zestawy warunków w funkcjach, których możesz używać w całym zestawie reguł. Reguły bezpieczeństwa obsługują funkcje niestandardowe. Składnia funkcji niestandardowych jest podobna do JavaScript, ale Firebase Security Rules funkcje są pisane w języku specyficznym dla domeny który ma pewne ważne ograniczenia:
- Funkcje mogą zawierać tylko jedną instrukcję
return. Nie mogą zawierać żadnej dodatkowej logiki. Nie mogą na przykład wykonywać pętli ani wywoływać usług zewnętrznych. - Funkcje mogą automatycznie uzyskiwać dostęp do funkcji i zmiennych z zakresu, w którym są zdefiniowane. Na przykład funkcja zdefiniowana w zakresie
service firebase.storagema dostęp do zmiennejresource, a w przypadku Cloud Firestore – tylko do wbudowanych funkcji takich jakget()iexists(). - Funkcje mogą wywoływać inne funkcje, ale nie mogą być rekurencyjne. Łączna głębokość stosu wywołań jest ograniczona do 10.
- W wersji
rules2funkcje mogą definiować zmienne za pomocą słowa kluczowegolet. Funkcje mogą mieć dowolną liczbę powiązań let, ale muszą kończyć się instrukcją return.
Funkcja jest definiowana za pomocą słowa kluczowego function i przyjmuje 0 lub więcej argumentów. Możesz na przykład połączyć 2 typy warunków używane w powyższych przykładach w jedną funkcję:
service firebase.storage {
match /b/{bucket}/o {
// True if the user is signed in or the requested data is 'public'
function signedInOrPublic() {
return request.auth.uid != null || resource.data.visibility == 'public';
}
match /images/{imageId} {
allow read, write: if signedInOrPublic();
}
match /mp3s/{mp3Ids} {
allow read: if signedInOrPublic();
}
}
}
Używanie funkcji w Firebase Security Rules ułatwia ich utrzymanie w miarę wzrostu złożoności reguł.
Dalsze kroki
Po omówieniu warunków masz bardziej zaawansowaną wiedzę o regułach i możesz:
Dowiedzieć się, jak obsługiwać podstawowe przypadki użycia, oraz poznać proces tworzenia, testowania i wdrażania reguł:
- Pisać reguły, które rozwiązują typowe problemy.
- Poszerzać swoją wiedzę, analizując sytuacje, w których musisz wykrywać i unikać niezabezpieczonych reguł.
- Testować reguły za pomocą emulatora Cloud Storage i specjalnej biblioteki testowej reguł bezpieczeństwa.
- Sprawdzić metody dostępne do wdrażania Security Rules.