git 1be1791e0168323f0e23b50fd7b64794e53709c6
В дополнение к предоставленным из коробки службам аутентификации , Laravel также предоставляет простой способ авторизовать действия пользователя в отношении данного ресурса. Как и в случае с аутентификацией, подход Laravel к авторизации прост, и есть два основных способа авторизации действий: "шлюзы"(Gates) и "политики"(Policies).
Думайте о шлюзах и политиках, как маршрутах и контроллерах. Шлюзы обеспечивают простое решение на основе замыканий, в свою очередь политики, как контроллеры, группируют свою логику вокруг конкретной модели или ресурса. Сначала мы разберем шлюзы, а затем изучим политики.
Важно не рассматривать шлюзы и политики как взаимоисключающие вещи. Большинство приложений, скорее всего, содержат смесь шлюзов и политик, и это прекрасно! Шлюзы наиболее применимы к действиям, которые не связаны с какой-либо моделью или ресурсом, например, просмотр панели администратора. В противоположность этому, политика должна быть использована, если вы хотите разрешить действие для конкретной модели или ресурса.
Шлюзы - это замыкания, которые определяют, имеет ли пользователь право выполнить данное действие. И обычно, определяются в классе App\Providers\AuthServiceProvider
с помощью фасада Gate
. Шлюз всегда получает экземпляр пользователя в качестве первого аргумента. Так же они могут принимать дополнительные аргументы, например, соотвтетствующую модель Eloquent:
/**
* Register any authentication / authorization services.
*
* @return void
*/
public function boot()
{
$this->registerPolicies();
Gate::define('update-post', function ($user, $post) {
return $user->id == $post->user_id;
});
}
Чтобы авторизовать действие с помощью шлюза, вы должны использовать метод allows
. Обратите внимание, что вам не нужно передавать текущего, аутентификацированного пользователя в метод allows
. Laravel автоматически подставит текущего пользователя в замыкание:
if (Gate::allows('update-post', $post)) {
// Текущий пользователь может обновить пост...
}
Если вы хотите определить, авторизован ли конкретный пользователь для выполнения действия, вы можете использовать метод forUser
фасада Gate
:
if (Gate::forUser($user)->allows('update-post', $post)) {
// Пользователь может обновить пост...
}
Политики являются классами, организующими логику авторизации вокруг конкретной модели или ресурса. Например, если ваше приложение является блогом, вы можете иметь модель Post
и соответствующую PostPolicy
для авторизации действия пользователя, таких как создание или обновление постов.
Вы можете создать политику, используя команду artisan make:policy
. Сформированная политика будет помещена в каталог app/Policies
. Если этот каталог не существует в приложении, Laravel создаст его:
php artisan make:policy PostPolicy
Команда make:policy
создаст пустой класс политики. Если вы хотите создать класс c базовыми "CRUD" методами уже включенными в политику, вы можете указать опцию --model
при выполнении команды:
php artisan make:policy PostPolicy --model=Post
Все политики создаются через Laravel сервис-контейнер, это позволяет внедрять любые необходимые зависимости в конструктор этой политики, эти зависимости будут разрешены автоматически.
После того, как политика была создана, она должна быть зарегистрирована. AuthServiceProvider
входящий в состав свежеустановленного приложения Laravel содержит свойство policies
, которое сопоставляет ваши Eloquent модели соответствующим политикам. Регистрация политики будет указывать Laravel, какую политику использовать при авторизации действия для данной модели:
<?php
namespace App\Providers;
use App\Post;
use App\Policies\PostPolicy;
use Illuminate\Support\Facades\Gate;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
class AuthServiceProvider extends ServiceProvider
{
/**
* The policy mappings for the application.
*
* @var array
*/
protected $policies = [
Post::class => PostPolicy::class,
];
/**
* Register any application authentication / authorization services.
*
* @return void
*/
public function boot()
{
$this->registerPolicies();
//
}
}
После того, как политика была зарегистрирована, вы можете добавить методы для всех действий, которые она авторизует. Например, давайте определим метод update
нашего класса PostPolicy
, который определяет, может ли данный пользователь User
обновить данный экземпляр Post
.
Метод update
получит User
'a и экземпляр Post
в качестве аргументов, и он должен вернуть true
или false
, указывающее имеет ли пользователь право обновлять данный Post
. В данном примере, давайте проверим, что id
пользователя соответствует user_id
на поста:
<?php
namespace App\Policies;
use App\User;
use App\Post;
class PostPolicy
{
/**
* Determine if the given post can be updated by the user.
*
* @param \App\User $user
* @param \App\Post $post
* @return bool
*/
public function update(User $user, Post $post)
{
return $user->id === $post->user_id;
}
}
Вы можете ghjl определять дополнительные методы по мере необходимости политики для различных действий, которые он санкционирует. Например, вы можете определить методы view
(просмотр) или delete
(удаление) для авторизации различных действий над моделью Post
. И не забывайте, что вольны называть методы ваших политик как вам хочется.
Если вы использовали опцию
--model
при создании вашей политики из консоли Artisan, она уже будет включать методы для действийview
,create
,update
иdelete
.
Некоторые методы политики получиают только текущего аутентифицированного пользователя но не экземпляр модели, действие над которой они авторизуют. Такая ситуация чаще всего встерчается при авторизации действия create
. Например, если вы создаете блог, вы можете проверить, имеет ли пользователь право создавать какие либо посты.
При определении метода политики, которая не получает экземпляр модели, например метод create
вы должны определить метод, который ожидет на вход только аутентифицированного пользователя:
/**
* Determine if the given user can create posts.
*
* @param \App\User $user
* @return bool
*/
public function create(User $user)
{
//
}
Если вы использовали опцию
--model
при создании вашей политики, все соответствующие политики "CRUD"-методы уже будут определены в сгенерированной политике.
Для некоторых пользователей, вы можете разрешить все действия в рамках данной политики. Для достижения этой цели, определите метод before
. Метод before
будет выполняться перед любыми другими методами политики, это даст вам возможность авторизовать действия до того, как конкретный метод политики будет выполнен. Эта функция наиболее часто используется для авторизации выполнения каких-либо действий администратором приложения:
public function before($user, $ability)
{
if ($user->isSuperAdmin()) {
return true;
}
}
Модель User
, которая поставляется с Laravel включает в себя две полезных метода для авторизации действий: can
и cant
. Метод can
принимает действие, которое вы хотите разрешить и соответствующую модель. Например, давайте определим, имеет ли пользователь право обновлять данную модель Post
:
if ($user->can('update', $post)) {
//
}
Если для данной модели зарегистрирована политика , метод can
будет автоматически вызывать соответствующую политику и вернет булево значение. Если для данной модели политика не зарегистрирована метод can
попытается вызвать замыкание шлюза, соответствующее данному названию действия.
Как вы помните, некоторые действия, такие как create
не могут требовать экземпляр модели. В таких ситуациях, вы можете передать в метод can
имя класса. Имя класса будет использоваться для определения того, какие политики использовать при авторизации действия:
use App\Post;
if ($user->can('create', Post::class)) {
// Executes the "create" method on the relevant policy...
}
Laravel включает в себя посредники, которые могут авторизовать действия до того, как входящий запрос достигнет маршрутов или контроллеров. По умолчанию, в App\Http\Kernel
посреднику Illuminate\Auth\Middleware\Authorize
назначен ключ can
. Давайте рассмотрим пример использования посредника can
для авторизации пользователя может на обновление поста в блоге:
use App\Post;
Route::put('/post/{post}', function (Post $post) {
// The current user may update the post...
})->middleware('can:update,post');
В этом примере мы передаем в посредник can
два аргумента. Первый - это имя действия, которое мы хотим разрешить, а второй - имя параметра маршрута, который мы хотим передать методу политики. В этом случае, так как мы используем неявную привязку модели, модель Post
будет передана методу политики. Если пользователь не имеет права выполнить данное действие, посредником будет сгенерирован HTTP-ответ с кодом 403
.
Опять же, некоторые действия, такие как create
не могут требовать экземпляр модели. В таких ситуациях, вы можете передать в посредник имя класса. Имя класса будет использоваться для определения того, какие политики будут использоваться при авторизации действия:
Route::post('/post', function () {
// Текущий пользователь может создать пост...
})->middleware('can:create,App\Post');
В дополнение к полезным методам, предусмотренным в модели User
, Laravel предоставляет еще один полезный метод authorize
в любом из контроллеров, которые расширяют базовый класс App\Http\Controllers\Controller
. Как и метод can
, этот метод принимает имя действия вы хотите разрешить и соответствующую модель. Если действие не разрешено, то authorize
сгенерирует исключение Illuminate\Auth\Access\AuthorizationException
, которое обработчик исключений Laravel преобразует в ответ HTTP с статус кодом 403
:
<?php
namespace App\Http\Controllers;
use App\Post;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
class PostController extends Controller
{
/**
* Update the given blog post.
*
* @param Request $request
* @param Post $post
* @return Response
*/
public function update(Request $request, Post $post)
{
$this->authorize('update', $post);
// The current user can update the blog post...
}
}
Как обсуждалось ранее, некоторые действия, например create
не могут требовать экземпляр модели. В таких случаях, вы можете передать имя класса в метод authorize
. Имя класса будет использоваться для определения того, какие политики будут использоваться при авторизации действия:
/**
* Create a new blog post.
*
* @param Request $request
* @return Response
*/
public function create(Request $request)
{
$this->authorize('create', Post::class);
// The current user can create blog posts...
}
При написании шаблонов Blade, вам может понадобиться отобразить часть страницы, только если пользователь авторизован выполнить данное действие. Например, вы можете показать форму обновления для в блоге, только если пользователь действительно может обновить пост. В этом случае, вы можете использовать директивы @can
и @cannot
.
@can('update', $post)
<!-- Текущий пользователь может обновить пост -->
@endcan
@cannot('update', $post)
<!-- Текущий пользователь не может обновить пост -->
@endcannot
Эти директивы являются удобными краткими записями @if
и @unless
. Директивы @can
и @cannot
указанные выше можно разложить как:
@if (Auth::user()->can('update', $post))
<!-- Текущий пользователь может обновить пост -->
@endif
@unless (Auth::user()->can('update', $post))
<!-- Текущий пользователь не может обновить пост -->
@endunless
Как и большинство других методов авторизации, вы можете передать имя класса в @ законсервирует
и @ cannot
директивы, если действие не требует экземпляра модели:
@can('create', Post::class)
<!-- Текущий пользователь может создать пост -->
@endcan
@cannot('create', Post::class)
<!-- Текущий пользователь не может создать пост -->
@endcannot