Доступ разрешен, доступ запрещен

Отступление 8.5

На данный момент переведено

В этой главе вы:

  • Узнаете про функции Allow и Deny.
  • Разберетесь в каком порядке эти функции вызываются.
  • Система защиты данных Meteor позволяет контролировать редактирование базы данных без необходимости создавать каждый раз отдельный Метод.

    Так как нам нужно было несколько вспомогательных задач для добавления дополнительных полей к посту, а также специальных действий когда URL поста уже был опубликован ранее, использование специального Метода post имело смысл.

    С другой стороны, нам не нужно было создавать Методы для редактирования и удаления постов. Достаточно было проверить, разрешено ли пользователю совершать эти действия - и это было очень просто сделать с помощью проверок allow и deny.

    С помощью этих коллбеков мы можем явно объявить, какие операции редактирования базы данных разрешены. Дополнительным бонусом является тот факт, что они неплохо интегрируются с системой пользовательских аккаунтов.

    Множественные коллбеки

    Мы можем объявить столько коллбеков allow, сколько нам понадобится. Чтобы операция прошла проверку достаточно если один из них вернет true. Когда Posts.insert вызывается браузером (из консоли браузера, или со страницы нашего приложения), сервер в свою очередь будет вызывать все доступные проверки операции insert до тех пор, пока одна из них не вернет true. Если ни одной из проверок нет, или все они возвращают false, сервер вернет ошибочный статус 403.

    Точно так же мы можем создать одну или несколько проверок deny. Если хотя бы одна из них вернет true, изменения будут отменены и статус 403 будет сгенерирован сервером. Для успешной операции insert в базе данных будут вызваны один или несколько allow insert проверок, а также все проверки deny insert.

    Внимание: n/e означает Не Выполнено (Not Executed)
    Внимание: n/e означает Не Выполнено (Not Executed)

    Другими словами, Meteor двигается по листу проверок сверху вниз. Сначала он проходит все проверки deny, затем allow, и вызывает все функции-коллбеки до тех пор, пока одна из них не вернет true.

    Приведем наглядный пример. Две проверки allow() - первая проверяет соответствие авторства поста текущему пользователю, а вторая выясняет, есть ли у пользователя права администратора. Если текущий пользователь админ, одна из этих проверок гарантировано вернет true, и таким образом мы разрешаем ему редактирование всех постов.

    Компенсация задержки передачи данных

    Если вы помните, все Методы отвечающие за изменение базы данных (такие как .update()) содержат компенсацию задержки передачи данных (равно как и любые другие Методы). Если вы, скажем, попробуете удалить пост который вам не принадлежит через консоль браузера, вы увидите как пост на мгновение исчезнет, когда локальная коллекция удалит этот пост. Чуть позже он появится назад, когда сервер сообщит что нет, документ не был удален.

    Разумеется, подобное поведение пользовательского интерфейса не проблема, когда пользователи играются с консолью - до тех пор пока все изменения ограничиваются их браузером. С другой стороны, вам стоит отразить доступные действия в интерфейсе приложения. Например, надо потратить какое-то время на код, чтобы кнопка удаления поста не появлялась с документами, которые пользователю не разрешено удалять.

    К счастью, вы можете создать общие правила доступа для клиента и сервера. Например, вы можете написать библиотечную функцию canDeletePost(user, post) и сохранить ее в общей папке /lib.

    Права доступа на сервере

    Обратите внимание что система ограничения доступа распространяется только на операции с базой данных, пришедшие со стороны клиента. На сервере Meteor предполагает что все операции разрешены.

    Это означает, что если вы создадите Метод Meteor под названием deletePost и сделаете его доступным для вызова на клиенте, любой пользователь сможет удалить любой пост. Скорее всего вы этого не хотите, за исключением если внутри Метода не проверяются права пользователя на удаление постов.

    Используем deny как коллбек

    Наконец, еще один способ использовать deny - воспользоваться им в качестве коллбека onX. Например, вы могли бы добавлять дату и время lastModified к постам следующим образом:

    Posts.deny({
      update: function(userId, doc, fields, modifier) {
        doc.lastModified = +(new Date());
        return false;
      },
      transform: null
    });
    

    Так как проверки deny вызываются для каждой операции update, мы знаем что эта операция будет гарантированно вызвана, и соответствующие изменения будут внесены в документ перед его сохранением в базу данных.

    Эта техника все же отдает запахом хака, поэтому возможно вы захотите обновлять содержимое документов в соответствующем Методе. Не смотря на это, нам будет полезно знать о таком подходе. Возможно, в будущем появится коллбек в стиле beforeUpdate для официального выполнения кода перед тем как документ сохранен.