Как ограничить дочернее свойство при чтении родительского списка
У меня есть следующая схема базы данных:
{
"events": {
"$eventId": {
"eventTitle": "Go shopping",
"participants": {
"0": {
"id": "0",
"name": "John Smith"
},
"1": {
"id": "1",
"name": "Jason Black"
}
}
}
}
}
Это массив событий, где каждое событие имеет список участников. Как сделать правило базы данных, где:
- каждый может получить событие или список событий,
- При получении события, полный список участников может быть виден только администратором,
- при получении события, если пользователь является участником события, список участников будет получать только он, никто другой,
- при получении события, если пользователь не является участником, список участников будет пустым
Вот моя попытка в схеме правил:
{
"rules": {
"events": {
".read": true,
"$eventKey": {
"eventTitle": {
".validate": "newData.isString() && newData.val().length < 100"
},
"participants": {
".read": "root.child('users/'+auth.uid+'/role').val() === 'ADMIN'",
".validate": "newData.hasChildren()",
"$participantKey": {
".read": "($participantKey === auth.uid || root.child('users/'+auth.uid+'/role').val() === 'ADMIN')",
"id": {
".validate": "newData.val() === $participantKey"
},
"name": {
".validate": "newData.isString() && newData.val().length < 100"
}
}
}
}
}
}
}
Это не работает, потому что, когда я читаю список событий, это не уважает .read
ограничение в participants
а также $participantKey
поля. Он просто получает полный список участников все время.
@edit
Другими словами. У меня есть эти упрощенные правила:
{
"events": {
".read": true,
"$eventKey": {
"participants": {
".read": false
}
}
}
}
Когда я запрашиваю: events/{eventKey}/participants
Я все еще получаю предмет с участниками, хотя participants
флаг чтения установлен в false
,
Но когда я удаляю .read
флаг от events
, затем извлекая данные .read
флаг в participants
,
@edit2
Из документации:
Правило.read, которое предоставляет разрешение на чтение местоположения, также позволяет читать любые потомки этого местоположения, даже если у потомков есть свои собственные.read правила, которые не выполняются.
Мой вопрос сейчас, как опустить это правило?
2 ответа
Firebase разрешения каскадно вниз. После того как вы дали пользователю разрешение на определенном уровне в дереве JSON, вы не можете отозвать это разрешение на более низком уровне в дереве.
Это означает, что эти правила не будут работать:
{
"events": {
".read": true,
"$eventKey": {
"participants": {
".read": false
}
}
}
}
".read": false
игнорируется Firebase.
Вместо этого вам придется структурировать ваши данные таким образом, чтобы соответствовать вашим требованиям безопасности. Это делается путем полного разделения типов данных, которые имеют различные требования безопасности.
{
"events": {
".read": true,
"$eventKey": {
"participants": {
".read": false
}
}
}
"eventparticipants": {
".read": false
"$eventKey": {
/* This is where you store the participants */
}
}
}
Итак, у вас есть два списка верхнего уровня: events
а также eventparticipants
, В списках используются те же ключи для объектов под ними: идентификатор события. Но поскольку это два списка верхнего уровня, один может быть общедоступным, а другой более ограниченным.
Документация Firebase рекомендует не использовать массивы при добавлении данных в базу данных. Основная проблема в вашем коде состоит в том, что вы используете массив, который является анти-паттерном, когда дело доходит до Firebase.
Одна из многих причин, по которым Firebase рекомендует не использовать массивы, заключается в том, что это делает невозможным написание правил безопасности, и это ваш случай.
Поскольку Firebase является базой данных NoSQL и потому что она структурирована как пары ключ и valeu, решение заключается в использовании Map
а не массив. Измените способ добавления данных в базу данных, и ваша проблема будет решена.