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

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

+ myapp
  + users
    + john
      + email: "john@mail.com"
      + roles
        + administrator: true
    + mary
      + email: "mary@mail.com"
      + roles
        + moderator: true
    + ...
  + documents
    + -JVmo6wZM35ZQr0K9tJu
      + ...
    + -JVr56hVTZxlAI5AgUaS
      + ...
    + ...

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

{
  "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"
    }
  }
}

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

теперь мои сомнения:

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

1 ответов


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

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

+ myapp
  + users
    + twitter:2544215
      + email: "john@mail.com"
      + roles
        + administrator: true
    + twitter:2544216
      + email: "mary@mail.com"
      + 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 в форму ответа)