Ten przewodnik opiera się na poznawaniu podstawowej składni języka reguł zabezpieczeń Firebase i pokazuje, jak dodawać warunki do reguł zabezpieczeń Firebase dla Cloud Storage.
Podstawowym elementem składowym reguł zabezpieczeń Cloud Storage jest warunek. Warunek to wyrażenie logiczne, które określa, czy dana operacja powinna być dozwolona czy odrzucona. W przypadku podstawowych reguł najlepiej sprawdza się użycie literałów true
i false
. Jednak reguły zabezpieczeń Firebase dla Cloud Storage
pozwalają na pisanie bardziej złożonych warunków, które:
- Sprawdzanie uwierzytelniania użytkowników
- Weryfikuj dane przychodzące
Uwierzytelnianie
Reguły zabezpieczeń Firebase dla Cloud Storage integrują się z Uwierzytelnianiem Firebase, aby zapewnić zaawansowane uwierzytelnianie oparte na użytkownikach w Cloud Storage. Zapewnia to szczegółową kontrolę dostępu na podstawie deklaracji tokena uwierzytelniania Firebase.
Gdy uwierzytelniony użytkownik wysyła żądanie do Cloud Storage, zmienna request.auth
jest zapełniana identyfikatorem uid
(request.auth.uid
) użytkownika oraz deklaracji JWT (request.auth.token
) uwierzytelniania Firebase.
Dodatkowo podczas korzystania z niestandardowego uwierzytelniania w polu request.auth.token
wyświetlane są dodatkowe deklaracje.
Gdy nieuwierzytelniony użytkownik wykonuje żądanie, zmienna request.auth
ma wartość null
.
Korzystając z tych danych, istnieje kilka popularnych sposobów uwierzytelniania do zabezpieczania plików:
- Publiczna: ignoruj użytkownika
request.auth
- Uwierzytelniony prywatny: sprawdź, czy
request.auth
nie jest typunull
- Prywatny użytkownik: sprawdź, czy
request.auth.uid
równa się ścieżceuid
- Grupa prywatna: sprawdź, czy deklaracje tokena niestandardowego pasują do wybranego żądania, lub odczytaj metadane pliku, aby sprawdzić, czy istnieje pole metadanych.
Publiczny
Reguła, która nie uwzględnia kontekstu request.auth
, może być uznawana za regułę public
, ponieważ nie uwzględnia kontekstu uwierzytelniania użytkownika.
Reguły te mogą być przydatne przy udostępnianiu 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"); }
Uwierzytelniony prywatny
W niektórych przypadkach możesz chcieć, aby dane były dostępne dla wszystkich uwierzytelnionych użytkowników aplikacji, ale nie dla nieuwierzytelnionych. Zmienna request.auth
ma wartość null
w przypadku wszystkich nieuwierzytelnionych użytkowników, więc wystarczy, że sprawdzisz, czy zmienna request.auth
istnieje, aby wymagać uwierzytelnienia:
// Require authentication on all internal image reads match /internal/{imageId} { allow read: if request.auth != null; }
Prywatny użytkownik
Najczęstszym przypadkiem użycia request.auth
jest udzielanie poszczególnym użytkownikom szczegółowych uprawnień do ich plików: od przesyłania zdjęć profilowych po czytanie dokumentów prywatnych.
Pliki w Cloud Storage mają pełną „ścieżkę” do pliku, dlatego aby plik sterowany przez użytkownika był unikalnym elementem w prefiksie nazwy pliku (takim jak uid
użytkownika), który można sprawdzić, gdy reguła jest sprawdzana:
// 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; }
Prywatna grupa
Innym równie często spotykanym przypadkiem użycia jest przyznawanie uprawnień grupie do obiektu, np. umożliwienie kilku członkom zespołu współpracy nad udostępnionym dokumentem. Można to zrobić na kilka sposobów:
- utworzyć token niestandardowy uwierzytelniania Firebase, który zawiera dodatkowe informacje o członku grupy (np. identyfikator grupy);
- Dołącz informacje o grupie (takie jak jej identyfikator lub lista autoryzowanych
uid
) w metadanych pliku.
Gdy te dane zostaną zapisane w tokenie lub metadanych pliku, można się do nich odwołać z poziomu reguły:
// 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; }
Poproś o ocenę
Przesłane, pobrane pliki, zmiany w metadanych i usunięcia są oceniane przy użyciu request
wysłanego do Cloud Storage. Oprócz unikalnego identyfikatora użytkownika i ładunku uwierzytelniania Firebase w obiekcie request.auth
, jak opisano powyżej, zmienna request
zawiera ścieżkę pliku, w której jest wykonywane żądanie, czas otrzymania żądania i nową wartość resource
, jeśli żądanie dotyczy zapisu.
Obiekt request
zawiera też unikalny identyfikator użytkownika i ładunek uwierzytelniania Firebase w obiekcie request.auth
, co wyjaśniamy dokładniej w sekcji Bezpieczeństwo oparte na użytkownikach w tej dokumentacji.
Pełną listę właściwości obiektu request
znajdziesz poniżej:
Właściwość | Typ | Opis |
---|---|---|
auth |
mapa<ciąg, ciąg> | Po zalogowaniu się użytkownik udostępnia identyfikator uid , jego unikalny identyfikator, oraz token mapę deklaracji JWT uwierzytelniania Firebase. W przeciwnym razie będzie to null . |
params |
mapa<ciąg, ciąg> | Mapa zawierająca parametry zapytania żądania. |
path |
ścieżka | path reprezentujący ścieżkę, na której wykonywane jest żądanie. |
resource |
mapa<ciąg, ciąg> | Nowa wartość zasobu, obecna tylko w żądaniach write .
|
time |
sygnatura czasowa | Sygnatura czasowa określająca czas oceny żądania przez serwer. |
Ocena zasobów
Przy ocenie reguł warto też ocenić metadane przesyłanego, pobieranego, zmodyfikowanego lub usuniętego pliku. Dzięki temu można tworzyć złożone, zaawansowane reguły, które na przykład zezwalają na przesyłanie tylko plików o określonych typach treści lub usuwanych tylko pliki o określonym rozmiarze.
Reguły zabezpieczeń Firebase dla Cloud Storage udostępniają metadane pliku w obiekcie resource
, który zawiera pary klucz-wartość metadanych wyświetlanych w obiekcie Cloud Storage. Te właściwości można sprawdzać po otrzymaniu żądań read
lub write
, aby zapewnić integralność danych.
W przypadku żądań write
(np. przesyłania, aktualizowania i usuwania) oprócz obiektu resource
, który zawiera metadane pliku istniejącego obecnie w ścieżce żądania, możesz też używać obiektu request.resource
, który zawiera podzbiór metadanych pliku do zapisania, o ile zapis jest dozwolony. Możesz użyć tych 2 wartości, aby zapewnić integralność danych lub egzekwować 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, | Generowanie obiektów w Google Cloud Storage tego obiektu. |
metageneration |
int, | Metageneracja obiektu w Google Cloud Storage tego obiektu. |
size |
int, | Rozmiar obiektu w bajtach. |
timeCreated |
sygnatura czasowa | Sygnatura czasowa określająca czas utworzenia obiektu. |
updated |
sygnatura czasowa | Sygnatura czasowa określająca czas ostatniej aktualizacji obiektu. |
md5Hash |
string, | Skrót MD5 obiektu. |
crc32c |
string, | Skrót crc32c obiektu. |
etag |
string, | 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 |
mapa<ciąg, ciąg> | 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
.
Większe możliwości dzięki Cloud Firestore
Możesz uzyskać dostęp do dokumentów w Cloud Firestore, aby ocenić inne kryteria autoryzacji.
Za pomocą funkcji firestore.get()
i firestore.exists()
reguły zabezpieczeń mogą oceniać żądania przychodzące względem dokumentów w Cloud Firestore.
Funkcje firestore.get()
i firestore.exists()
oczekują w pełni określonych ścieżek dokumentu. Jeśli do tworzenia ścieżek dla firestore.get()
i firestore.exists()
używasz zmiennych, musisz za pomocą składni $(variable)
wyraźnie zmienić znaczenie zmiennych.
W przykładzie poniżej widać regułę, która ogranicza dostęp do odczytu plików do użytkowników należących do 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)).memberships } } }W następnym przykładzie tylko znajomi użytkownika mogą zobaczyć jego zdjęcia.
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)) } } }
Po utworzeniu i zapisaniu pierwszych reguł zabezpieczeń Cloud Storage korzystających z tych funkcji Cloud Firestore w konsoli Firebase lub w interfejsie wiersza poleceń Firebase pojawi się prośba o przyznanie uprawnień do połączenia 2 usług.
Możesz wyłączyć tę funkcję, usuwając rolę uprawnień zgodnie z opisem w artykule Wdrażanie reguł zabezpieczeń Firebase i zarządzanie nimi.
Zweryfikuj dane
Reguł zabezpieczeń Firebase dla Cloud Storage można też używać do weryfikacji danych, w tym do weryfikacji nazwy i ścieżki pliku oraz właściwości metadanych pliku, np. 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
W miarę jak reguły zabezpieczeń Firebase stają się coraz bardziej złożone, być może warto połączyć zestawy warunków w funkcje, których możesz używać w zestawie reguł. Reguły zabezpieczeń obsługują funkcje niestandardowe. Składnia funkcji niestandardowych przypomina JavaScript, ale funkcje reguł zabezpieczeń Firebase są napisane w języku specyficznym dla danej domeny, który ma pewne ważne ograniczenia:
- Funkcje mogą zawierać tylko jedną instrukcję
return
. Nie mogą zawierać żadnej dodatkowej logiki. Nie mogą np. uruchamiać pętli ani wywoływać usług zewnętrznych. - Funkcje mogą automatycznie uzyskiwać dostęp do funkcji i zmiennych
z zakresu, w którym zostały zdefiniowane. Na przykład funkcja zdefiniowana w zakresie
service firebase.storage
ma dostęp do zmiennejresource
, a w przypadku Cloud Firestore dostępne są funkcje wbudowane, takie jakget()
iexists()
. - Funkcje mogą wywoływać inne funkcje, ale nie mogą się powtarzać. Łączna głębokość stosu wywołań jest ograniczona do 10.
- W wersji
rules2
funkcje mogą definiować zmienne za pomocą słowa kluczowegolet
. Funkcje mogą mieć dowolną liczbę powiązań Let, ale muszą kończyć się instrukcją zwrotną.
Funkcja jest zdefiniowana za pomocą słowa kluczowego function
i przyjmuje zero lub więcej argumentów. Możesz na przykład połączyć 2 rodzaje warunków użytych 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();
}
}
}
Korzystanie z funkcji w regułach zabezpieczeń Firebase ułatwia ich obsługę wraz ze wzrostem złożoności reguł.
Dalsze kroki
Po omówieniu warunków stajemy się bardziej skomplikowani w zasadach i możemy:
Dowiedz się, jak obsługiwać podstawowe przypadki użycia i jak wygląda przepływ pracy przy tworzeniu, testowaniu i wdrażaniu reguł:
- Napisać reguły dotyczące typowych scenariuszy.
- Poszerzaj swoją wiedzę, sprawdzając sytuacje, w których musisz rozpoznawać niezabezpieczone Reguły i ich unikać.
- Przetestuj reguły za pomocą emulatora Cloud Storage i dedykowanej biblioteki testowej reguł zabezpieczeń.
- Przejrzyj dostępne metody wdrażania reguł.