Firebase: установить правила безопасности в зависимости от пользовательских ролей

Я хотел бы реализовать правила безопасности "write" в Firebase в зависимости от ролей пользователей.
Моя структура данных выглядит так:

+ myapp
  + users
    + john
      + email: "[email protected]"
      + roles
        + administrator: true
    + mary
      + email: "[email protected]"
      + roles
        + moderator: true
    + ...
  + documents
    + -JVmo6wZM35ZQr0K9tJu
      + ...
    + -JVr56hVTZxlAI5AgUaS
      + ...
    + ...

Например, я хочу, чтобы только пользователи-пользователи могли писать документы.
Это правила, к которым я пришел:

{
  "rules": {
    ".read": true,
    "$documents": {
      ".write": "root.child('users').child(auth.uid).child('roles').child('administrator').val() === true"
    }
  }
}

Но это не работает: даже пользователи-администраторы не могут писать документы...
Является ли мое понимание правил безопасности Firebase совершенно ошибочным?

ОБНОВЛЕНИЕ: Как раз перед тем, как Дженни ответит (верьте или нет :-), я реализовал то же самое решение, которое он предоставляет (конечно, на основе комментария Като).
Хотя, делая некоторые тесты, я не мог позволить структуре правил

{
  "rules": {
    "documents" {
      "$document" {
        ".read": "root.child('users').child(auth.uid).child('roles').child('documents').child('read').val() === true",
        ".write": "root.child('users').child(auth.uid).child('roles').child('documents').child('write').val() === true"
      }
    }
  }
}

работа... У меня всегда было предупреждение:

"FIREBASE WARNING: on() or once() for /documents failed: Error: permission_denied: Client doesn't have permission to access the desired data. "

Поэтому я придумал эту структуру, вместо этого:

{
  "rules": {
    "documents" {
      ".read": "root.child('users').child(auth.uid).child('roles').child('documents').child('read').val() === true",
      ".write": "root.child('users').child(auth.uid).child('roles').child('documents').child('write').val() === true"
    }
  }
}

Что действительно работает для меня: если я задаю роли /customers/read node true для пользователя, он может прочитать все документы, иначе он не сможет (и то же самое для записи).

Теперь я сомневаюсь:

  • почему я не мог допустить, чтобы первое правило (как было предложено Като) работает?
  • видите ли вы какое-либо возможное отверстие безопасности в правиле, подобном тому, которое я сделал?
  • являются правилами, использующими переменные "$", необходимыми/полезными, даже если вам не нужно разрешать/запрещать читаемость/возможность записи каждого отдельного документа на основе этого ключа, но вы просто хотите разрешить/запретить читабельность/удобочитаемость узла как целое?

Ответ 1

Основываясь на именах ваших пользовательских записей, они не соответствуют auth.uid, который, вероятно, является простейшим идентификатором входа, например twitter:2544215.

Начните с настройки ваших пользователей, которые будут храниться через их простой вход uid:

+ myapp
  + users
    + twitter:2544215
      + email: "[email protected]"
      + roles
        + administrator: true
    + twitter:2544216
      + email: "[email protected]"
      + roles
        + moderator: true
    + ...
  + documents
    + -JVmo6wZM35ZQr0K9tJu
      + ...
    + -JVr56hVTZxlAI5AgUaS
      + ...
    + ...

Затем добавьте правило безопасности, чтобы администраторы могли обращаться к documents. У вас есть пара вариантов здесь, в зависимости от вашего конкретного варианта использования.

  1. Чтобы администраторы могли писать доступ к содержимому каждого документа:

    {
      "rules": {
        "documents": {
          "$documents": {
            ".write": "root.child('users').child(auth.uid).child('roles').child('administrator').val() === true"
          }
        }
      }
    }
    
  2. Или, альтернативно, предоставить им доступ ко всей коллекции:

    {
      "rules": {
        "documents": {
          ".write": "root.child('users').child(auth.uid).child('roles').child('administrator').val() === true"
        }
      }
    }
    

Разница между этими двумя является переменной $documents которая перемещает правило безопасности на один шаг дальше в иерархию.

(Это было всего лишь совокупность комментариев @Kato в форме ответа)