Firebase Security Rules для Cloud Storage используются для определения того, кто имеет доступ на чтение и запись к файлам, хранящимся в Cloud Storage , а также как структурированы файлы и какие метаданные они содержат. Cloud Storage Security Rules состоят из правил, которые учитывают request
и resource
, чтобы разрешить или запретить желаемое действие, например загрузку файла или получение метаданных файла. В этих справочных документах описаны типы правил, свойства request
и resource
, типы данных, используемые Cloud Storage Security Rules , а также способы возникновения ошибок.
Правило
rule
— это выражение, которое оценивается, чтобы определить, разрешено ли request
выполнить желаемое действие.
Типы
Позволять
Правила allow
состоят из метода, например read
или write
, а также необязательного условия. Когда правило выполняется, условие оценивается, и если условие оценивается как true
, желаемый метод разрешен; в противном случае метод отклоняется. Правило allow
без условий всегда разрешает нужный метод.
// Always allow method allow <method>; // Allow method if condition is true allow <method>: if <condition>;
В настоящее время allow
— единственный поддерживаемый тип правила.
Методы запроса
Читать
Метод read
охватывает все запросы, в которых читаются данные или метаданные файла, включая загрузку файлов и чтение метаданных файлов.
// Always allow reads allow read; // Allow reads if condition evaluates to true allow read: if <condition>;
Писать
Метод write
охватывает все запросы, в которых записываются данные или метаданные файла, включая загрузку файлов, удаление файлов и обновление метаданных файлов.
// Always allow writes allow write; // Allow writes if condition evaluates to true allow write: if <condition>;
Соответствовать
Правила выполняются, когда request
пользователя (например, загрузка или загрузка файла) соответствует пути к файлу, охватываемому правилом. match
состоит из пути и тела, которое должно содержать хотя бы одно allow
правило. Если ни один путь не найден, запрос отклоняется.
Вы можете match
полностью именованный путь или вставить подстановочные знаки, чтобы сопоставить все пути, соответствующие определенному шаблону.
Сегменты пути
single_segment
Вы можете использовать отдельные сегменты пути, чтобы создать правило, соответствующее файлу, хранящемуся в Cloud Storage .
// Allow read at "path" if condition evaluates to true match /path { allow read: if <condition>; }
Также разрешены несколько сегментов пути и вложенные пути:
// Allow read at "path/to/object" if condition evaluates to true match /path { match /to { match /object { allow read: if <condition>; } } }
{single_segment_wildcard}
Если вы хотите применить правило к нескольким файлам по одному и тому же пути, вы можете использовать сегмент пути с подстановочными знаками, чтобы сопоставить все файлы по определенному пути. Переменная с подстановочным знаком объявляется в пути путем заключения переменной в фигурные скобки: {variable}
. Эта переменная доступна в операторе match как string
.
// Allow read at any path "/*", if condition evaluates to true match /{single_path} { // Matches "path", "to", or "object" but not "path/to/object" allow read: if <condition>; }
Несколько сегментов пути и вложенные пути также могут иметь подстановочные знаки:
// Allow read at any path "/path/*/newPath/*", if condition evaluates to true match /path/{first_wildcard} { match /newPath/{second_wildcard} { // Matches "path/to/newPath/newObject" or "path/from/newPath/oldObject" allow read: if <condition>; } }
{multi_segment_wildcard=**}
Если вы хотите сопоставить любое количество сегментов пути на пути или ниже, вы можете использовать подстановочный знак из нескольких сегментов, который будет соответствовать всем запросам до местоположения и ниже. Это может быть полезно для предоставления пользователю собственного свободного пространства для хранения или создания правил, соответствующих множеству различных сегментов пути (например, создание общедоступного набора файлов или требование аутентификации для всех операций записи).
Многосегментный путь с подстановочными знаками объявляется аналогично односегментному подстановочному знаку, с добавлением =**
в конце переменной: {variable=**}
. Многосегментная подстановочная переменная доступна в операторе сопоставления как объект path
.
// Allow read at any path "/**", if condition evaluates to true match /{multi_path=**} { // Matches anything at or below this, from "path", "path/to", "path/to/object", ... allow read: if <condition>; }
Запрос
Переменная request
предоставляется в условии, представляющем запрос, сделанный по этому пути. Переменная request
имеет ряд свойств, которые можно использовать для принятия решения о разрешении входящего запроса.
Характеристики
auth
Когда аутентифицированный пользователь выполняет запрос к Cloud Storage , переменная auth
заполняется uid
пользователя ( request.auth.uid
), а также утверждениями JWT Firebase Authentication ( request.auth.token
).
request.auth.token
содержит некоторые или все следующие ключи:
Поле | Описание |
---|---|
email | Адрес электронной почты, связанный с учетной записью, если таковой имеется. |
email_verified | true , если пользователь подтвердил, что у него есть доступ к адресу email . Некоторые провайдеры автоматически проверяют принадлежащие им адреса электронной почты. |
phone_number | Номер телефона, связанный с учетной записью, если он присутствует. |
name | Отображаемое имя пользователя, если оно установлено. |
sub | UID пользователя Firebase. Это уникально в рамках проекта. |
firebase.identities | Словарь всех идентификаторов, связанных с учетной записью этого пользователя. Ключами словаря могут быть любые из следующих: email , phone , google.com , facebook.com , github.com , twitter.com . Значения словаря представляют собой массивы уникальных идентификаторов для каждого поставщика удостоверений, связанного с учетной записью. Например, auth.token.firebase.identities["google.com"][0] содержит первый идентификатор пользователя Google, связанный с учетной записью. |
firebase.sign_in_provider | Поставщик входа, использованный для получения этого токена. Может быть одной из следующих строк: custom , password , phone , anonymous , google.com , facebook.com , github.com , twitter.com . |
firebase.tenant | TenantId, связанный с учетной записью, если он присутствует. например tenant2-m6tyz |
При использовании пользовательской аутентификации request.auth.token
также содержит любые пользовательские утверждения, указанные разработчиком.
Когда неаутентифицированный пользователь выполняет запрос, request.auth
имеет значение null
.
// Allow requests from authenticated users allow read, write: if request.auth != null;
path
Переменная path
содержит путь, по которому выполняется request
.
// Allow a request if the first path segment equals "images" allow read, write: if request.path[0] == 'images';
resource
Переменная resource
содержит метаданные загружаемого файла или обновленные метаданные существующего файла. Это связано с переменной resource
, которая содержит метаданные текущего файла по запрошенному пути, а не новые метаданные.
// Allow a request if the new value is smaller than 5MB allow read, write: if request.resource.size < 5 * 1024 * 1024;
request.resource
содержит следующие свойства из resource
:
Свойство |
---|
name |
bucket |
metadata |
size |
contentType |
time
Переменная time
содержит временную метку, представляющую текущее время на сервере, в которое обрабатывается запрос. Вы можете использовать это для предоставления доступа к файлам на основе времени, например: разрешать загрузку файлов только до определенной даты или разрешать чтение файлов только в течение часа после их загрузки.
// Allow a read if the file was created less than one hour ago allow read: if request.time < resource.timeCreated + duration.value(1, 'h');
Предусмотрено множество функций для написания правил с использованием временных меток и длительности .
Ресурс
Переменная resource
содержит метаданные файлов в Cloud Storage , такие как имя файла, размер, время создания и пользовательские метаданные.
Характеристики
name
Строка, содержащая полное имя файла, включая путь к файлу.
// Allow reads if the resource name is "path/to/object" allow read: if resource.name == 'path/to/object'
bucket
Строка, содержащая сегмент Google Cloud Storage, в котором хранится этот файл.
// Allow reads of all resources in your bucket allow read: if resource.bucket == '<your-cloud-storage-bucket>'
generation
Целое число, содержащее созданный объект Google Cloud Storage для файла. Используется для управления версиями объектов.
// Allow reads if the resource matches a known object version allow read: if resource.generation == <known-generation>
metageneration
Целое число, содержащее метагенерацию объекта Google Cloud Storage файла. Используется для управления версиями объектов.
// Allow reads if the resource matches a known object metadata version allow read: if resource.metageneration == <known-generation>
size
Целое число, содержащее размер файла в байтах.
// Allow reads if the resource is less than 10 MB allow read: if resource.size < 10 * 1024 * 1024;
timeCreated
Временная метка, указывающая, когда был создан файл.
// Allow reads if the resource was created less than an hour ago allow read: if resource.timeCreated < request.time + duration.value(60, "m")
updated
Временная метка, показывающая, когда файл был последний раз обновлен.
// Allow reads if the resource was updated less than an hour ago allow read: if resource.updated < request.time + duration.value(60, "m")
md5Hash
Строка, содержащая MD5-хеш файла.
// Allow writes if the hash of the uploaded file is the same as the existing file allow write: if request.resource.md5Hash == resource.md5Hash;
crc32c
Строка, содержащая хэш crc32c файла.
// Allow writes if the hash of the uploaded file is the same as the existing file allow write: if request.resource.crc32c == resource.crc32c;
etag
Строка, содержащая etag файла.
// Allow writes if the etag matches a known object etag allow write: if resource.etag == <known-generation>
contentDisposition
Строка, содержащая расположение содержимого файла.
// Allow reads if the content disposition matches a certain value allow read: if resource.contentDisposition == 'inlined';
contentEncoding
Строка, содержащая кодировку содержимого файла.
// Allow reads if the content is encoded with gzip allow read: if resource.contentEncoding == 'gzip';
contentLanguage
Строка, содержащая язык содержимого файла.
// Allow reads if the content language is Japanese allow read: if resource.contentLanguage == 'ja';
contentType
Строка, содержащая тип содержимого файла.
// Allow reads if the content type is PNG. allow read: if resource.contentType == 'image/png';
metadata
Map<String, String>
, содержащий дополнительные поля метаданных, предоставленные разработчиком.
// Allow reads if a certain metadata field matches a desired value allow read: if resource.metadata.customProperty == 'customValue';
firestore.get и firestore.exists
Функции firestore.get()
и firestore.exists()
позволяют получать доступ к документам в Cloud Firestore для оценки сложных критериев авторизации.
Обе функции firestore.get()
и firestore.exists()
ожидают полностью заданных путей к документам. При использовании переменных для создания путей для firestore.get()
и firestore.exists()
вам необходимо явно экранировать переменные, используя синтаксис $(variable)
.
firestore.get
Получите содержимое документа Cloud Firestore .
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.uid)).data.memberships } } }
firestore.exists
Проверьте, существует ли документ Cloud Firestore .
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.uid)) } } }
Услуга
service
является первым объявлением в файле Cloud Storage Security Rules и указывает, к какой службе будут применяться эти правила.
Имя
name
К имени будут применяться правила сервиса. Единственное текущее значение — firebase.storage
.
// Specify the service name service firebase.storage { match /b/{bucket}/o { ... } }
Типы данных
Язык Rules позволяет проверять тип с помощью оператора is
.
// For example
a is null
a is string
null
Тип данных null
представляет несуществующее значение.
allow read: if request.auth != null;
bool
Тип bool
представляет логическое значение true
или false
.
allow read: if true; // always succeeds allow write: if false; // always fails
Сравнение
Логические значения можно сравнивать с помощью операторов ==
!=
.
Логические операции
Операция | Выражение |
---|---|
AND | x && y |
OR | x || y |
NOT | !x |
Операции являются коротким замыканием и могут возвращать true
, false
или Error .
allow read: if true || false; // always succeeds, short circuits at true allow write: if false && true; // always fails, short circuits at false
int
и float
Типы int
и float
представляют числа. Целые числа: 0
, 1
, -2
и т. д., а числа с плавающей запятой: 1.0
, -2.0
, 3.33
и т. д.
Целые числа — это 64-битные значения со знаком, а числа с плавающей точкой — 64-битные значения, соответствующие стандарту IEEE 754. Значения типа int
будут принудительно преобразованы в число с float
при использовании в сравнениях и арифметических операциях со значением float
.
Сравнение
Целые числа и числа с плавающей запятой можно сравнивать и упорядочивать с помощью операторов ==
, !=
, >
, <
, >=
и <=
.
Арифметика
Целые числа и числа с плавающей запятой можно складывать, вычитать, умножать, делить, модулировать и отрицать:
Операция | Выражение |
---|---|
Добавление | x + y |
Вычитание | x - y |
Умножение | x * y |
Разделение | x / y |
по модулю | x % y |
Отрицание | -x |
Математические функции
Firebase Security Rules для Cloud Storage также предоставляют ряд вспомогательных математических функций для упрощения выражений:
Функция | Описание |
---|---|
math.ceil(x) | Потолок числового значения |
math.floor(x) | Минимальное числовое значение |
math.round(x) | Округлите входное значение до ближайшего целого числа |
math.abs(x) | Абсолютное значение входа |
math.isInfinite(x) | Проверяет, равно ли значение ±∞ , возвращает bool |
math.isNaN(x) | Проверьте, не является ли значение числом NaN , возвращает bool |
string
Сравнение
Строки можно лексографически сравнивать и упорядочивать с помощью операторов ==
, !=
, >
, <
, >=
и <=
.
Конкатенация
Строки можно объединить с помощью оператора +
.
// Concatenate a file name and extension 'file' + '.txt'
Индекс и диапазон
Оператор index
string[]
возвращает строку, содержащую символ по указанному индексу в строке.
// Allow reads of files that begin with 'a' match /{fileName} { allow read: if fileName[0] == 'a'; }
Оператор range
string[i:j]
возвращает строку, содержащую символы между указанными индексами, от i
(включительно) до j
(исключительно). Если i
или j
не указаны, они по умолчанию равны 0 и размеру строки соответственно, но для того, чтобы диапазон был допустимым, необходимо указать хотя бы i
или j
.
// Allow reads of files that begin with 'abcdef' match /{fileName} { allow read: if fileName[0:6] == 'abcdef'; }
Операторы index
и range
выдадут ошибку, если предоставленные индексы выходят за границы строки.
size
Возвращает количество символов в строке.
// Allow files with names less than 10 characters match /{fileName} { allow write: if fileName.size() < 10; }
matches
Выполняет сопоставление с регулярным выражением и возвращает true
, если строка соответствует данному регулярному выражению. Использует синтаксис Google RE2 .
// Allow writes to files which end in ".txt" match /{fileName} { allow write: if fileName.matches('.*\\.txt') }
split
Разбивает строку в соответствии с предоставленным регулярным выражением и возвращает list
строк. Использует синтаксис Google RE2 .
// Allow files named "file.*" to be uploaded match /{fileName} { allow write: if fileName.split('.*\\..*')[0] == 'file' }
path
Пути — это имена, подобные каталогам, с необязательным сопоставлением с образцом. Наличие косой черты /
обозначает начало сегмента пути.
path
Преобразует string
аргумент в path
.
// Allow reads on a specific file path match /{allFiles=**} { allow read: if allFiles == path('/path/to/file'); }
timestamp
Временные метки указаны в формате UTC, возможные значения начинаются с 0001-01-01T00.00.00Z и заканчиваются 9999-12-31T23.59.59Z.
Сравнение
Временные метки можно сравнивать и упорядочивать с помощью операторов ==
, !=
, >
, <
, >=
и <=
.
Арифметика
Временные метки поддерживают сложение и вычитание между временными метками и продолжительностями следующим образом:
Выражение | Результат |
---|---|
timestamp + duration | timestamp |
duration + timestamp | timestamp |
timestamp - duration | timestamp |
timestamp - timestamp | duration |
duration + duration | duration |
duration - duration | duration |
date
Значение timestamp
, содержащее только year
, month
и day
.
// Allow reads on the same day that the resource was created. allow read: if request.time.date() == resource.timeCreated.date()
year
Значение года в виде целого числа от 1 до 9999.
// Allow reads on all requests made before 2017 allow read: if request.time.year() < 2017
month
Значение месяца в виде целого числа от 1 до 12.
// Allow reads on all requests made during the month of January allow read: if request.time.month() == 1;
day
Текущий день месяца в формате int, от 1 до 31.
// Allow reads on all requests made during the first day of each month allow read: if request.time.day() == 1;
time
Значение duration
, содержащее текущее время.
// Allow reads on all requests made before 12PM allow read: if request.time.time() < duration.time(12, 0, 0, 0);
hours
Значение часов представляет собой целое число от 0 до 23.
// Allow reads on all requests made before 12PM allow read: if request.time.hours() < 12;
minutes
Значение минут в виде целого числа от 0 до 59.
// Allow reads during even minutes of every hour allow read: if request.time.minutes() % 2 == 0;
seconds
Значение секунд в виде целого числа от 0 до 59.
// Allow reads during the second half of each minute allow read: if request.time.seconds() > 29;
nanos
Доли секунды в нано как целое число.
// Allow reads during the first 0.1 seconds of each second allow read: if request.time.nanos() < 100000000;
dayOfWeek
День недели: от 1 (понедельник) до 7 (воскресенье).
// Allow reads on weekdays (Monday to Friday) allow read: if request.time.dayOfWeek() < 6;
dayOfYear
День текущего года, от 1 до 366.
// Allow reads every fourth day allow read: if request.time.dayOfYear() % 4 == 0;
toMillis
Возвращает текущее количество миллисекунд, прошедших с эпохи Unix.
// Allow reads if the request is made before a specified time allow read: if request.time.toMillis() < <milliseconds>;
duration
Значения продолжительности представлены в виде секунд плюс доли секунды в наносекундах.
Сравнение
Длительности можно сравнивать и упорядочивать с помощью операторов ==
, !=
, >
, <
, >=
и <=
.
Арифметика
Длительности поддерживают сложение и вычитание между метками времени и длительностью следующим образом:
Выражение | Результат |
---|---|
timestamp + duration | timestamp |
duration + timestamp | timestamp |
timestamp - duration | timestamp |
timestamp - timestamp | duration |
duration + duration | duration |
duration - duration | duration |
seconds
Количество секунд в текущей продолжительности. Должно быть между -315 576 000 000 и +315 576 000 000 включительно.
nanos
Количество долей секунды (в наносекундах) текущей продолжительности. Должно быть от -999 999 999 до +999 999 999 включительно. Для ненулевых секунд и ненулевых наносекунд знаки обоих должны совпадать.
duration.value
Длительность можно создать с помощью функции duration.value(int magnitude, string units)
, которая создает длительность времени на основе заданной величины и единицы измерения.
// All of these durations represent one hour: duration.value(1, "h") duration.value(60, "m") duration.value(3600, "s")
Возможные unit
измерения:
Продолжительность | unit |
---|---|
Недели | w |
Дни | d |
Часы | h |
Минуты | m |
Секунды | s |
Миллисекунды | ms |
Наносекунды | ns |
duration.time
Длительность можно создать с помощью функции duration.time(int hours, int minutes, int seconds, int nanoseconds)
, которая создает длительность времени в заданные часы, минуты, секунды и наносекунды.
// Create a four hour, three minute, two second, one nanosecond duration duration.time(4, 3, 2, 1)
list
Список содержит упорядоченный массив значений, который может иметь тип: null
, bool
, int
, float
, string
, path
, list
, map
, timestamp
или duration
.
Учитывая x
и y
list
типов и i
и j
типа int
Создание
Чтобы создать список, добавьте значения в скобках:
// Create a list of strings ['apples', 'grapes', 'bananas', 'cheese', 'goats']
Сравнение
Списки можно сравнивать с помощью операторов ==
!=
. Равенство двух списков требует, чтобы все значения были равны.
Индекс и диапазон
Оператор index
list[]
возвращает элемент по указанному индексу в списке.
// Allow reads of all files that begin with 'a' match /{fileName} { allow read: if fileName[0] == 'a'; }
Оператор range
list[i:j]
возвращает все элементы списка между указанными индексами от i
(включительно) до j
(исключительно). Если i
или j
не указаны, они по умолчанию равны 0 и размеру списка соответственно, но для того, чтобы диапазон был действительным, необходимо указать хотя бы i
или j
.
// Allow reads of all files that begin with 'abcdef' match /{fileName} { allow read: if fileName[0:6] == 'abcdef'; }
in
Возвращает true
, если желаемое значение присутствует в списке, или false
, если оно отсутствует.
// Allow read if a filename has the string 'txt' in it match /{fileName} { allow read: if 'txt' in fileName.split('\\.'); }
join
Объединяет список строк в одну строку, разделенную заданной строкой.
// Allow reads if the joined array is 'file.txt' allow read: if ['file', 'txt'].join('.') == 'file.txt';
size
Количество элементов в списке.
// Allow read if there are three items in our list allow read: if ['foo', 'bar', 'baz'].size() == 3;
hasAll
Возвращает true
, если в списке присутствуют все значения.
// Allow read if one list has all items in the other list allow read: if ['file', 'txt'].hasAll(['file', 'txt']);
map
Карта содержит пары ключ/значение, где ключи представляют собой строки, а значения могут быть любыми из: null
, bool
, int
, float
, string
, path
, list
, map
, timestamp
или duration
.
Создание
Чтобы создать карту, добавьте пары ключ/значение между фигурными скобками:
// Create a map of strings to strings { 'mercury': 'mars', 'rain': 'cloud', 'cats': 'dogs', }
Сравнение
Карты можно сравнивать с помощью операторов ==
!=
. Равенство двух карт требует, чтобы все ключи присутствовали на обеих картах и все значения были равны.
Индекс
Доступ к значениям на карте осуществляется с помощью скобок или точечной записи:
// Access custom metadata properties allow read: if resource.metadata.property == 'property' allow write: if resource.metadata['otherProperty'] == 'otherProperty'
Если ключ отсутствует, будет возвращена error
.
in
Возвращает true
, если нужный ключ присутствует в карте, или false
, если он отсутствует.
// Allow reads if a property is present in the custom metadata allow read: if property in resource.metadata;
size
Количество ключей в карте.
// Allow reads if there's exactly one custom metadata key allow read: if resource.metadata.size() == 1;
keys
Список всех ключей на карте.
// Allow reads if the first metadata key is 'myKey' allow read: if resource.metadata.keys()[0] == 'myKey';
values
Список всех значений на карте в ключевом порядке.
// Allow reads if the first metadata value is 'myValue' allow read: if resource.metadata.values()[0] == 'myValue';
Ошибки
Оценка ошибок
Firebase Security Rules для Cloud Storage продолжают оценку при обнаружении ошибок. Это полезно, поскольку условные операторы &&
и ||
выражения могут поглощать ошибку, если в противном случае условное выражение превратилось бы в false
или true
соответственно. Например:
Выражение | Результат |
---|---|
error && true | error |
error && false | false |
error || true | true |
error || false | error |
Распространенными местами возникновения ошибок являются: деление на ноль, доступ к значениям в списке или карте, которые не существуют, а также передача значений неправильного типа в функцию.
// Error if resource.size is zero allow read: if 1000000 / resource.size; // Error, key doesn't exist allow read: if resource.metadata.nonExistentKey == 'value'; // Error, no unit 'y' exists allow read: if request.time < resource.timeCreated + duration.value(1, 'y');