Как ограничить дочернее свойство при чтении родительского списка

У меня есть следующая схема базы данных:

{
    "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 а не массив. Измените способ добавления данных в базу данных, и ваша проблема будет решена.

Другие вопросы по тегам