Главная Ларавел Авторизация в Laravel. Использование методов класса Gate.

Ларавел


Авторизация в Laravel. Использование методов класса Gate.

Авторизация – это процесс проверка прав пользователя на выполнение определенного действия. То есть, до начала процесса авторизации, пользователь уже должен быть аутентифицирован (залогинен) чтобы в коде можно было идентифицировать данного пользователя для проверки его прав. Хотя есть возможность проверить права и для любого другого пользователя. Про аутентификацию можно прочитать тут.

Удобным местом для размещения правил авторизации приложения является метод boot() класса AuthServiceProvider (файл app\Providers\AuthServiceProvider.php).

Правила авторизации в своей работе используют класс Gate (файл vendor\laravel\framework\src\Illuminate\Auth\Access\Gate.php). 
При этом вызов методов делается к алиасу данного класса.
Так, например, вызов метода
Gate::define();
устанавливает определенные правила, а вызов метода
Gate::denies()
используется при проверке разрешений для пользователей (подробнее ниже).


Опишу, что происходит при обращении к алиасу Gate.

При начальной загрузке приложения, вызываются методы register() классов провайдеров данных, указанных в массиве providers файла config\app.php. В нашем случае метод register() класса AuthServiceProvider:

public function register()
{
    $this->registerAuthenticator();
    $this->registerUserResolver();
    $this->registerAccessGate();
    $this->registerRequestRebindHandler();
}

в строке 

$this->registerAccessGate();

вызывается метод

protected function registerAccessGate()
{
    $this->app->singleton(GateContract::class, function ($app) {
        return new Gate($app, function () use ($app) {
            return call_user_func($app['auth']->userResolver());
        });
    });
}

который создает объект класса Gate, привязывая его к идентификатору «Illuminate\Contracts\Auth\Access\Gate» (вызов GateContract::class), название идентификатора передается из фасада Gate (файл vendor\laravel\framework\src\Illuminate\Support\Facades\Gate.php)

Для данного фасада в файле config\app.php создан алиас:

'Gate' => Illuminate\Support\Facades\Gate::class,


Поэтому обращаться к методам класса Gate можно так:
- подключение

use Gate;

- вызов методов

Gate::denies();


То есть, при вызове методов, обращение происходит к классу Gate из файла vendor\laravel\framework\src\Illuminate\Auth\Access\Gate.php

Как я уже писал, правила авторизации удобно прописывать в сервис-провайдере - app\Providers\AuthServiceProvider.php в методе boot() после строки

$this->registerPolicies();

данная строка добавляет к проверке политики, составленные для моделей, указанных в свойстве выше - protected $policies. Это отдельный способ создание проверки для авторизации рассмотренный в другой статье.


Например нужно разрешить доступ к созданию новых постов (действие контроллера по созданию постов) только пользователям с правами админа.
 

Пример вызова анонимной функции для проверки авторизации:

Gate::define('add-post', function ($user) {
    foreach($user->roles as $role){
if($role->name == 'admin') return true; 
    }
    return false;
});

после алиаса Gate вызов метода denies(), который 
- первым параметром принимает название правила (произвольное);
- второй параметр функция или контроллер@действие для выполнения

$user – объект текущего пользователя, передается в функцию первым аргументом всегда. Можно передать так же другие аргументы для функции при вызове из действия контроллера.

При создании связей таблиц, была создана связь «многие ко многим» для таблиц users и roles через связывающую таблицу. Поэтому для того, чтобы получить роли для текущего пользователя (в $user- объект текущего пользователя), нужно вызвать динамическое свойство roles:

$user->roles

которое возвращает коллекцию объектов ролей для текущего пользователя. Т.к. это коллекция (массив), нужно пройтись циклом и сравнить название ролей пользователя с той, которая разрешает доступ.

Вызов проверки осуществляется в контроллере, в нужном методе:

if(Gate::denies('add-post')){
    return redirect()->back()->with('message','Доступ запрещен.');
}


Тут могут использоваться такие методы класса Gate:

  • denies() – определяет, следует ли отказать в доступе к указанному праву (добавление постов). Другими словами - отказывает в авторизации, если из Gate::define() получено false;
  • allows() обратен методу denies() и возвращает true, если действие авторизовано;
  • check() — псевдоним метода allows().

В данном примере, если пользователь не будет иметь нужных прав, его перенаправит на предыдущую страницу с сообщением в сессии «Доступ запрещен.»

 

Пример вызова метода контроллера для проверки авторизации:

Gate::define('add-post',  \App\Http\Controllers\admin\AdminPostController::class.'@access');


в методе access AdminPostControllerа все указывается так же, как в функции:

public function access($user){
    foreach($user->roles as $role){
if($role->name == 'admin') return true; 
    }    
    return false;
}

 



Еще пример - нужно разрешить доступ на редактирование поста только пользователю - автору данного поста или пользователям с правами админа.
Правило, прописанное в методе boot() класса AuthServiceProvider может выглядеть так:

Gate::define('update-post', function($user, $post){

foreach($user->roles as $role){
    if($role->name == 'admin'){
        return true;
    }
}

if ($user->id == $post->user_id){
    return true;
}

    return false;
});


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

$post = Post::find($request->id);
if(Gate::denies('update-post', $post)){
    return redirect()->back()->with('message', 'Доступ запрещен.');
}


Если вашему праву необходимо несколько аргументов, просто передайте массив аргументов в методы Gate:

if (Gate::allows('delete-comment', [$post, $comment])) {
    //
}

 

Перехват проверок авторизации.

Есть возможность использовать события, которые выполнятся перед или после авторизации.
Метод Gate::before() выполнится перед вызовом Gate::denies(). Если он вернет какой-то результат (true | false), то метод авторизации Gate::denies() уже выполняться не будет.

Gate::before(function ($user, $ability) {
    if ($user->isSuperAdmin()) {
        return true;
    }
});

где:
$user – объект текущего пользователя;
$ability – название правила из класса, перед которым сработает вызов анонимной функции.
Далее любая нужная проверка возвращающая результат или же просто выполнение нужного кода (тогда не прописывать return).
Данный метод можно вызывать как в контроллере, так и в AuthServiceProvider и в классе политики.

Так же есть аналогичный метод, который выполнит анонимную функцию после проведения авторизации. 
Но из этого метода нельзя изменить результат проверки авторизации:

Gate::after(function ($user, $ability, $result, $arguments) {
  //
});


Если нужно проверить права у пользователя, отличного от текущего аутентифицированного пользователя, то можно использовать метод forUser():
 

$user = \App\User::find(1);
if (Gate::forUser($user)->denies('update-post', $post)) {
    return redirect()->back()->with('message', 'Доступ запрещен.');
}

аргументом для метода forUser() является объект нужного пользователя


Проверка с помощью экземпляра модели User.

Альтернативный способ проверки прав — с помощью экземпляра модели User. Для этого существует 2 метода: can() и cannot(). Эти методы могут быть использованы так же, как методы allows() и denies() фасада Gate.

Пример.

if($request->user()->cannot('add-post')){
    return redirect()->back()->with('message','Доступ запрещен.');
}

Вызов $request->user() возвращает объект текущего пользователя.
Метод can() возвращает true если данному пользователю разрешается совершение проверяемых действий, а метод cannot()возвращает true если не разрешается.


 

Проверка в шаблонах Blade.

Для проверки используется директива check): ?>.
Пример – использование в шаблоне вывода формы для добавление поста:

@can('update-post', $post)
    <form action="{{route('admin_create_post_p')}}" method="POST" class="form-horizontal">
    …
    </form>
@else
    <div class="alert alert-danger">
        <h2>У Вас нет прав на изменение данных.</h2>
    </div>
@endcan


Есть еще возможность провести авторизацию после отправки заполненной формы пользователем, в случае, если для проверки отправленных данных (валидации) вы используете отдельные классы, хранимые в папке app\Http\Requests. О создании такого класса написано в разделе про валидацию Laravel. 

При создании данного класса используя консоль, будет размещен метод authorize():

public function authorize()
{
    return true;
}

который, по-умолчанию, возвращает true. Но в данном методе, можно прописать какую-то проверку с возвратом false в случае ее не прохождения.

Так же следует отметить, что Gate автоматически возвращает значение false для всех прав, когда нет аутентифицированного пользователя, или конкретный пользователь не был указан с помощью метода forUser().

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


Вы можете помочь развитию сайта отправив любую сумму

Комментарии

  1. uwiyupyijaub
    23.05.2019 в 03:31

    Класс.

  2. itluqaeti
    23.05.2019 в 04:02

    Что за хрень.

  3. awalipof
    05.06.2019 в 11:16

    Хорошая статья, благодарю.

  4. unawumaa
    05.06.2019 в 12:03

    Кат то не совсем понятно.

Написать комментарий