Комментарии 26
Почему решили делать свой класс Authorization
, а не встроиться в механизм политик?
Я попробую вспомнить и напишу вам.
Я поразмыслил немного, да и некоторые комментарии навели меня на определенные мысли.
Во-первых у меня было мало времени, т.к. нужно было срочно сделать вменяемую систему авторизации. \Gate:before() в этом контексте было приемлемым и очень элегантным решением — не нужно менять никаких предков, просто поставил и сразу все работает как нужно.
В связи с Policies сразу встал вопрос: как организовать иерархию операций? Тогда мне некогда было об этом думать серьезно.
Сегодня я поразмышлял на эту тему основательно и, в принципе, придумал способ встраивания. Но выглядит это как некоторое притягивание за уши… по крайней мере в нынешнем виденьи.
Конечно использование Policies несколько структурирует пермишины, но с другой стороны и усложняет восприятие целостной картины, а роли еще сильней усложнят ее. Вот и возникает вопрос: а нужно ли это усложнение для не слишком больших проектов? На мой взгляд — нет.
Да, свои могут. А, например, только статьи опубликованные за последний месяц?
Ну то есть, вы же понимаете, что там просто задействованы отношения, а здесь можно воротить что угодно.
Я очень внимательно изучил документацию и даже исходники (но не очень внимательно). И единственное, что я заметил
// You can also grant an ability only to a specific model
Bouncer::allow($user)->to('edit', $post);
совершенно не то, о чем мы говорим. Bouncer позволяет разрешить/запретить операцию с какой-то конкретной моделью. Можно глянуть из любопытства сюда:
- https://github.com/JosephSilber/bouncer/blob/master/src/Conductors/Concerns/AssociatesAbilities.php
- https://github.com/JosephSilber/bouncer/blob/master/src/Database/Queries/AbilitiesForModel.php
но если вы покажете мне, что где-то при проверке вызывается замыкание или еще что-то в этом роде, то буду вам премного благодарен. А пока я все-таки продолжу настаивать, что Bouncer не может разрешить редактировать только статьи, опубликованные за последний месяц.
Если бы автор там возвращал null, то всё так и работало бы.
Извиняюсь ещё раз за невнимательность)
Но все же, у этой библиотеки не все так гладко получается, особенно когда в проекте больше одного guard-а.
Хм… а никаких встроенных механизмов для этого нет! И это очень странно, т.к. в большинстве систем пользователи генерируют какой-то контент (например статьи) и должны иметь возможность его редактировать, при этом не имея доступа к редактированию чужого.
Серьёзно? Прям таки нет
В том месте, откуда взята эта цитата, речь шла о больших, серьезных модулях и что в них нет такого простого и нужного механизма (передача параметра в функцию-проверку).
В Laravel такой механизм есть и именно благодаря его наличию существует опираясь на эту инфраструктуру данный модуль.
Но в Laravel нет ролей и это обесценивает Policies на 90%. Фактически они превращаются в фильтры — если я сделаю как написано в примере:
class PostPolicy {
public function update(User $user, Post $post) {
return $user->id === $post->user_id;
}
}
то начну фильтровать всех пользователей. Как же мне тогда "менеджеру" разрешить редактировать все? Писать if? Куда? В код? Спасибо, не надо!
Или в метод update что-то вроде if($user->role=='manager')-elseif-elseif-else? Тоже увольте.
Вот и получается, что Policies есть, а применить их в реальном проекте затруднительно.
Спасибо. Хотелось бы увидеть такую-же статью о ABAC.
Есть статья "RBAC vs ABAC": https://habrahabr.ru/company/custis/blog/248649/
// All privileges without limitation (for admin and manager).
Gate::define('administer-users', function ($user) {
return $user->role == 'manager' || $user->role == 'admin';
});
Будет время, напишу об этом у себя в блоге: https://cleverman.org
Не вполне вас понял.
Как вы реализуете последовательность проверок в полисях? (update-post → update-post-in-category → update-own-post)
- В примере вы определяете пермишин в котором на самом деле проверяете роли… это очень странно, т.е. фактически это эквивалент проверки ролей в коде. В любой статье по RBAC (и в этой тоже) написано, что проверять роли в коде это идеологически неверно. В коде нужно проверять разрешения (операции).
Если в вашем примереadminister-users
больше не должны видеть какое-то меню, то нужно лезть в код и убиратьcan('administer-users')
бог знает в скольких местах и в каком-нибудь обязательно забыть… В случае вышеописанного модуля необходимо просто в настройках изъять операцию из роли администратора.
В полисах я сделал так:
public function destroyPost(User $user, Post $post)
{
return $user->id == $post->user_id || Gate::check('administer-users');
}
public function editPost(User $user, Post $post)
{
return $user->id == $post->user_id || Gate::check('administer-users');
}
Опять же таки, я решил пойти путем «с хвоста». Право 'administer-users' всегда дает доступ ко всему, у кого есть роль админ или менеджер. Есть еще право 'user-content' с ролью user (или любой другой, какую вы назначите). Вот именно оно всегда и везде проверяется. Если мне нужно всем владельцам закрыть возможность в редактировании своих постов, то не трогая контроллеры, можно просто вернуть false в полисе.
Если мне нужно вообще все запретить для авторизованных пользователей, то я верну false в проверке для права 'user-content'.
Плюс не стоит забывать еще тот момент, что мы работаем с фреймворком, и все бремя ответственности по разработке архитектуры ложится на программиста. Поэтому, было бы очень здорово продумать еще на начальной стадии разработки, что это за проект, каковы его цели, кому нужен доступ, а кому нет, что вообще должны делать пользователи, а что им нельзя. И исходя из этого уже создавать систему прав. А то, очень часто, вначале пилится проект, а потом уже думается, а что делать с ролями и правами. И начинается забег с костылями. Это сугубо мое личное мнение. Никому его не навязываю.
У меня есть один проект на Drupal 7, Best-House.org, так там в настройках прав есть 300!!! полей с доступом к тому или другому функционалу. Это все можно нащелкать мышкой (просмотр, редактирование, удаление, доступ к настройкам и т.д.) и это к каждому полю. После этого трэша, я сказал себе хватит. И упростил все до состоянии неотесанной доски.
Bouncer::allow($user)->to('edit', $post);
Здесь: https://habrahabr.ru/post/321678/#comment_10076076
я уже написал именно по этому поводу.
Laravel. Иерархический RBAC для самых маленьких