Правила Firestore: проверить данные не имеет поля - PullRequest
0 голосов
/ 10 сентября 2018

Таким образом, в настоящее время у меня есть две роли для всех пользователей: isAdmin и isReader.

Администратору разрешено читать и записывать данные, а Читателю разрешено читать данные.

Когда кто-то создает учетную запись, у него нет прав.Даже не isReader.Только администратор может изменять правила.

Вот как я планировал это сделать:

Когда кто-то создает учетную запись, я создаю документ в коллекции Users, например:

uid: user.uid,
email: user.email,
role: {
    isAdmin: false,
    isReader: false,
}

При каждом входе в систему я обновляю 'email' и uid, но оставляю role без изменений.Для обеспечения этого поведения у меня есть следующие правила:

match /Users/{userId} {
  allow read: if isOwner(userId) || isAdmin();
  allow create: if request.resource.data.hasAll(['uid', 'email', 'role']) && request.resource.data.role.isAdmin == false && request.resource.data.role.isReader == false;
  allow update: if resource.data.role == null || isAdmin();
}

function isAdmin() {
  return getUserData().role.isAdmin == true;
}

Я думаю, у меня есть 2 ошибки:

  1. по некоторым причинам data.hasAll(['uid', 'email', 'role']) не работает.Когда я удаляю эту часть, правило create работает как запланировано.

  2. resource.data.role == null не работает.Я намерен проверить, содержат ли данные какие-либо обновления для role, потому что я не могу допустить, чтобы они не были получены от администратора.Но по какой-то причине это не работает.

Есть идеи, что я делаю не так?Также моя стратегия сохраняет или есть способ, которым кто-то может "взломать" права Reader или Admin?

Ответы [ 2 ]

0 голосов
/ 10 сентября 2018

Похоже, это может быть хорошим вариантом использования для пользовательских утверждений авторизации. Вы можете установить определенные роли для пользователя в защищенной среде, как показано в this codelab . Ниже приведен пример настройки настраиваемой заявки на вашем сервере. Вы даже можете использовать Облачные Функции для этого. Я рекомендую вам проверить полный код Codelab, чтобы вы могли убедиться, что не каждый может запросить добавление пользовательских утверждений своему пользователю.

admin.auth().setCustomUserClaims(uid, {Admin: true}).then(() => {
// The new custom claims will propagate to the user's ID token the
// next time a new one is issued.
});

Затем вы можете проверить эти роли пользователя в ваших правилах безопасности.

service cloud.firestore {
  match /databases/{database}/documents {
    match /Users/{userId} {
      allow read: if request.auth.token.Owner == true || request.auth.token.Admin == true;
      allow create: request.auth.uid == userId && 
      request.resource.data.uid == request.auth.uid &&
      request.resource.data.email != null;
      allow update: request.auth.uid == userId || request.auth.token.Admin == true;
    }
  }
}

Обратите внимание, что все правила о "роли" были удалены, потому что они больше не нужны. Дайте мне знать, если у вас есть вопросы по реализации, потому что я пытаюсь сделать что-то еще об этом, поскольку это такая распространенная проблема.

0 голосов
/ 10 сентября 2018

request.resource.data.hasAll(['uid', 'email', 'role']) не работает, поскольку request.resource.data представляет собой Map, а не List. Вы должны использовать keys(), чтобы создать List из Map и убедиться, что определенные ключи существуют.

Что касается вашей второй проблемы, вам следует просто проверить, есть ли запись в roles: allow update: if !('roles' in request.writeFields) || isAdmin();. Это обеспечит сбой любых обновлений roles, если пользователь не является администратором.

о вашем секретном вопросе; Я вижу пару вопросов. Во-первых, любой может создавать неограниченное количество пользователей, что также означает, что любой администратор может создавать неограниченное количество других учетных записей администратора. Чтобы этого не случилось, я бы добавил в allow create еще один раздел, ограничивающий создание пользователя:

allow create: if userId == request.resource.data.uid
  && request.auth.uid == request.resource.data.uid
  && request.resource.data.hasAll(['uid', 'email', 'role'])
  && request.resource.data.role.isAdmin == false
  && request.resource.data.role.isReader == false;`

Во-вторых, любой может изменить их uid и попытаться выдать себя за кого-то другого. Очевидно, это не меняет uid, связанный с их токеном аутентификации, но в зависимости от того, как вы пишете остальные свои правила, бэкэнд-безопасность или даже отображение внешнего интерфейса, кто-то может использовать этот недостаток для использования вашего кода или другого пользователя. (потенциально админ). Вы можете убедиться, что никто не изменит свои uid, проверив, находится ли он в writeFields (, вам также понадобится предыдущее решение для обеспечения безопасности, чтобы они также не выдавали себя за себя при создании ).

allow update: if !('uid' in request.writeFields)
  && (!('roles' in request.writeFields) || isAdmin());

Надеюсь, это поможет.

...