"Авторизация в Laravel. Использование методов класса Gate."
Для большого проекта, правила стоит сохранять не в методе boot() класса AuthServiceProvider, а в отдельных классах политик, только подключая их в классе AuthServiceProvider в защищенном свойстве $policies.
Правила указанные в политиках привязываются к конкретной сущности - модели.
Для создания класса политики авторизации, удобно использовать консоль:
php artisan make:policy PostPolicyсоздастся папка и файл app\Policies\PostPolicy.php
В классе политики создаем методы проверок с названиями по которым будем к ним обращаться:
public function add($user){ foreach($user->roles as $role){ if($role->name == 'admin') return true; } return false; } public function update($user, $post){ foreach($user->roles as $role){ if($role->name == 'admin'){ return true; } } if ($user->id == $post->user_id){ return true; } return false; }код проверок идентичный тому, что прописывался в методе boot() класса AuthServiceProvider в предыдущей статье.
Так же можно делать перехват проверок авторизации с помощью методов before() и after(). При использовании политик, для их использования нужно создавать соответствующий метод в классе политики:
public function before($user){ if ($user->id == 2) return true; return false; }в данном случае, метод before() будет выполнен перед любым из методов проверок данного класса политики авторизации.
Зарегистрируем данную политику.
Файл app\Providers\AuthServiceProvider.php, массив'App\Model' => 'App\Policies\ModelPolicy',указанный в свойстве $policies удаляем, т.к. он только для примера.
Вместо него прописываем свою политику:
protected $policies = [ Post::class => PostPolicy::class, ];ключ массива – сущность к которой привязываем (модель);
значение массива – класс политики.
Проверка политик.
1. В нужном действии контроллера.
Подключение почти аналогичное тому, которое использовалось при подключении правил указанных в методе boot(). Только при работе с политиками, аргументом, после названия правила, нужно передать сущность для которой правило создавалось (модель) – класс или объект.Пример - проверим возможность добавления поста для текущего пользователя:
if(Gate::denies('add', Post::class)){ return redirect()->back()->with('message','Доступ запрещен.'); }
если в коде уже есть доступ к объекту, то его и передаем:
if(Gate::denies('add', $post)){ return redirect()->back()->with('message','Доступ запрещен.'); }где $post – объект модели Post.
Пример – проверим права на редактирование поста:
$post = Post::find($request->id); if(Gate::denies('update', $post)){ return redirect()->back()->with('message', 'Доступ запрещен.'); }в данном примере не пришлось менять ничего кроме названия правила, т.к. для получения id поста мы и так передавали объект модели Post.
2. В шаблонах Blade.
Аналогично будет работать и проверка в шаблонах с помощью директивы @can, где так же нужно только указать правильно имя:@can('update', $post) <form action="{{route('admin_create_post_p')}}" method="POST" class="form-horizontal"> … </form> @else <div class="alert alert-danger"> <h2>У Вас нет прав на изменение данных.</h2> </div> @endcan
3. С помощью модели User и методов can() и cannot().
if($request->user()->cannot('update',$post)){ return redirect()->back()->with('message', 'Доступ запрещен.'); }нужно не забывать передать вторым аргументом сущность с которой связана политика – класс или объект нужной модели.
4. С помощью функции Policy.
Данная функция получает в качестве параметра класс или объект к которой привязана политика авторизации и возвращает объект данной политики, например PostPolicy. У которого далее вызывается нужный метод проверки правил. В данный метод нужно самому передать объект текущего пользователя.$user = Auth::user(); if(!policy(Post::class)->add($user)){ return redirect()->back()->with('message', 'Доступ запрещен.'); }после аргумента $user можно передать прочие, нужные аргументы.
Для того, чтобы данная проверка соответствовала проверке с помощью вызова Gate::denies() – перед вызовом я поставил восклицательный знак (инверсия возвращаемого значения true/false).
5. Авторизация контроллера.
Родительский контроллер App\Http\Controllers\Controller, от которого наследуются все пользовательские контроллеры, подключает трейт AuthorizesRequests из файла vendor\laravel\framework\src\Illuminate\Foundation\Auth\Access\AuthorizesRequests.phpДанный трейт содержит метод authorize(), который может быть использован для быстрой авторизации данного действия или выброса AuthorizationException. То есть, при отсутствии прав, действие контроллера обрывается с выводом исключения - HTTP-ответ с кодом состояния 403 Not Authorized.
public function authorize($ability, $arguments = []) { list($ability, $arguments) = $this->parseAbilityAndArguments($ability, $arguments); return app(Gate::class)->authorize($ability, $arguments); }
Метод authorize() данного трейта возвращает результат вызова объекта класса Gate (файл vendor\laravel\framework\src\Illuminate\Auth\Access\Gate.php) для которого вызывается одноименный метод authorize() определяющий есть ли у пользователя права на совершение указанного действия.
Как видим, метод принимает только 2 аргумента. Вторым аргументом можно передать один из параметров или же массив параметров.
Примеры.
1. Добавление поста:
$this->authorize('add', Post::class);
2. Обновление поста:
$this->authorize('update', [Post::class, $post]);
Так же можно проверить права для пользователя, который не является текущим аутентифицированным пользователем:
$this->authorizeForUser($user, 'update', $post);
Имена методов политик авторизации.
Если название метода контроллера, в котором проверяются права, будет совпадать с названием метода политики авторизации, то название метода политики при проверке прав можно не указывать:$this->authorize($post);
я новичок, подскажите, что значит Post::class ? делаю по статье и никак не могу подключить к своему тестовому проекту.. как мартышка и очки(
ответ на комментарий sam от 05.10.2017
то же самое, что
С помощью конструкции ClassName::class можно получить строку с абсолютным именем класса.
В данном примере это строковое представление класса модели Post с его пространством имен.