Правила безопасности базы данных Firebase Realtime — это то, как вы защищаете свои данные от неавторизованных пользователей и защищаете свою структуру данных.
В этом кратком руководстве я объясню, как правильно настроить правила безопасности базы данных, чтобы только авторизованные пользователи имели доступ к данным для чтения или записи. Я также покажу вам, как структурировать ваши данные, чтобы их было легко защитить.
Проблема
Предположим, у нас есть данные JSON в нашей базе данных Firebase, как в примере ниже:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
{
«users» : {
«user1» : {
«firstName» : «Chike»,
«lastName» : «Mgbemena»,
«age»: «89»
«phoneNumber» : «07012345678»
},
«user2» : {
«firstName» : «Godswill»,
«lastName» : «Okwara»,
«age»: «12»
«phoneNumber» : «0701234»
},
«user3» : {
«firstName» : «Onu»,
«lastName» : 543,
«age»: 90
«phoneNumber» : «07012345678»
},
…
}
}
|
Глядя на базу данных, вы можете увидеть, что есть некоторые проблемы с нашими данными:
- Два пользователя (
user1
иuser3
) имеют одинаковые номера телефонов. Мы бы хотели, чтобы они были уникальными. -
user3
есть номер для фамилии, а не строка. -
user2
имеет только семь цифр в своем номере телефона вместо 11. - Значение возраста для
user1
иuser2
— это строка, аuser3
— это число.
Со всеми этими недостатками, выделенными в наших данных, мы потеряли целостность данных. В следующих шагах я покажу вам, как этого избежать.
Разрешительные правила
База данных Firebase реального времени имеет следующие типы правил:
Тип | функция |
---|---|
.read |
Описывает, разрешено ли чтение данных пользователям. |
.write |
Опишите, если и когда данные могут быть записаны. |
.validate |
Определяет, как будет выглядеть правильно отформатированное значение, имеет ли оно дочерние атрибуты, и тип данных. |
.indexOn |
Определяет дочерний элемент для индексации для поддержки упорядочения и запросов. |
Узнайте больше о них в документации Firebase .
Вот очень разрешающее правило для ключа users
в нашей базе данных.
01
02
03
04
05
06
07
08
09
10
11
|
{
«rules»: {
«users»: {
// users is readable by anyone
«.read»: true,
// users is writable by anyone
«.write»: true
}
}
}
|
Это плохо, потому что это дает любому возможность читать или записывать данные в базу данных. Любой может получить доступ к пути /users/
а также к более глубоким путям. Мало того, но на данные пользователей не налагается никакой структуры.
Правила контроля доступа
01
02
03
04
05
06
07
08
09
10
|
{
«rules»: {
«users»: {
«$uid»: {
«.read»: «auth.uid == $uid»,
«.write»: «auth.uid == $uid»,
}
}
}
}
|
С помощью этих правил мы контролируем доступ к записям пользователей, вошедшим в систему. Не только это, но пользователи могут только читать или записывать свои собственные данные. Мы делаем это с подстановочным знаком: $uid
. Это переменная, представляющая дочерний ключ (имена переменных начинаются с $
). Например, при доступе к пути /users/user1
$uid
равен "user1"
.
Далее мы используем переменную auth
, которая представляет аутентифицированного пользователя. Это предопределенная серверная переменная, предоставляемая Firebase. В строках 5 и 6 мы применяем ограничение доступности, согласно которому только аутентифицированный пользователь с тем же идентификатором, что и у записи пользователя, может читать или записывать свои данные. Другими словами, для каждого пользователя доступ на чтение и запись предоставляется для /users/<uid>/
, где <uid>
представляет текущий аутентифицированный идентификатор пользователя.
Другие переменные сервера Firebase:
now |
Текущее время в миллисекундах с начала эпохи Linux. |
root |
RuleDataSnapshot представляющий корневой путь в базе данных Firebase в том виде, в каком он существует до предпринятой операции. |
newData |
RuleDataSnapshot представляющий данные в том виде, в котором они будут существовать после предпринятой операции. Он включает в себя новые записываемые данные и существующие данные. |
data |
RuleDataSnapshot, представляющий данные в том виде, в каком они существовали до предпринятой операции. |
auth |
Представляет полезную нагрузку токена аутентифицированного пользователя. |
Узнайте больше об этих и других серверных переменных в документации Firebase .
Обеспечение структуры данных
Мы также можем использовать правила Firebase для наложения ограничений на данные в нашей базе данных.
Например, в следующих правилах, в строках 8 и 11, мы обеспечиваем правила, что любое новое значение для имени и фамилии должно быть строкой. В строке 14 мы удостоверяемся, что возраст — это число. Наконец, в строках 17 и 18 мы вводим значение телефонного номера в виде строки длиной 11.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
{
«rules»: {
«users»: {
«$uid»: {
«.read»: «auth.uid == $uid»,
«.write»: «auth.uid == $uid»,
«firstName»: {
«.validate»: «newData.isString()»
},
«lastName»: {
«.validate»: «newData.isString()»
},
«age»: {
«.validate»: «newData.isNumber()»
},
«phoneNumber»: {
«.validate»: «newData.isString() &&
newData.val().length == 11″
},
}
}
}
}
|
Но как мы можем предотвратить дублирование телефонных номеров?
Предотвращение дубликатов
Далее я покажу вам, как предотвратить дублирование телефонных номеров.
Шаг 1: Нормализация структуры данных
Первое, что нам нужно сделать, это изменить корневой путь для включения узла верхнего уровня /phoneNumbers/
. Таким образом, при создании нового пользователя мы также добавим номер телефона пользователя в этот узел, когда проверка будет успешной. Наша новая структура данных будет выглядеть следующим образом:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
{
«users» : {
«user1» : {
«firstName» : «Chike»,
«lastName» : «Mgbemena»,
«age»: 89,
«phoneNumber» : «07012345678»
},
«user2» : {
«firstName» : «Godswill»,
«lastName» : «Okwara»,
«age»: 12,
«phoneNumber» : «06034345453»
},
«user3» : {
«firstName» : «Onu»,
«lastName» : «Emeka»,
«age»: 90,
«phoneNumber» : «09034564543»
},
…
},
«phoneNumbers» : {
«07012345678»: «user1»,
«06034345453»: «user2»,
«09034564543»: «user3»,
…
}
}
|
Шаг 2. Применение новой структуры данных
Нам нужно изменить правила безопасности, чтобы обеспечить соблюдение структуры данных:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
{
«rules»: {
«users»: {
«$uid»: {
…
«phoneNumber»: {
«.validate»: «newData.isString() &&
newData.val().length == 11 &&
!root.child(‘phoneNumbers’).child(newData.val()).exists()»
},
}
}
}
}
|
Здесь мы проверяем, является ли номер телефона уникальным, проверяя, является ли он уже дочерним по отношению к /phoneNumbers/
с указанным номером телефона в качестве ключа. Другими словами, мы проверяем, что номер телефона еще не зарегистрирован пользователем. Если этого не произошло, то проверка прошла успешно, и операция записи будет принята, в противном случае она будет отклонена.
Ваше приложение должно будет добавить номер телефона в список телефонных номеров при создании нового пользователя, и оно должно будет удалить номер телефона пользователя, если этот пользователь будет удален.
Имитация правил проверки и безопасности
Вы можете смоделировать свои правила безопасности в консоли Firebase, нажав кнопку Simulator . Добавьте правила безопасности, выберите тип симуляции (чтение или запись), введите некоторые данные с путем и нажмите кнопку « Выполнить» :
Если значением имени является число, а не строка, проверка завершится неудачно и доступ на запись будет запрещен:
Вывод
Из этого краткого руководства вы узнали о правилах безопасности базы данных Firebase: как предотвратить несанкционированный доступ к данным и как обеспечить структурирование данных в базе данных.
Чтобы узнать больше о правилах безопасности базы данных Firebase, обратитесь к официальной документации . И ознакомьтесь с некоторыми другими нашими учебниками и курсами по Firebase здесь на Envato Tuts +!