1. Code
  2. PHP
  3. Laravel

Gates и Policies в Laravel

Сегодня мы обсудим систему авторизации веб-фреймворка Laravel. Фреймворк Laravel реализует авторизацию в виде gates и политик. После введения в gates и политики я продемонстрирую концепции, реализовав собственный пример.
Scroll to top

Russian (Pусский) translation by Masha Kolesnikova (you can also view the original English article)

Сегодня мы обсудим систему авторизации веб-фреймворка Laravel. Фреймворк Laravel реализует авторизацию в виде gates и политик. После введения в gates и политики я продемонстрирую концепции, реализовав собственный пример.

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

Если вы не знаете систему аутентификации Laravel, я бы настоятельно рекомендовал прочесть официальную документацию, которая предоставит вам практическое понимание предмета.

Подход Laravel к авторизации

К настоящему времени вы уже должны знать, что система авторизации Laravel поставляется в двух вариантах - gates и политиках. Хотя это может показаться сложным, я бы сказал, что на самом деле все достаточно легко!

Gates позволяют вам определить правило авторизации, используя простой подход, основанный на замыканиях. Другими словами, если вы хотите разрешить действие, которое не связано с какой-либо конкретной моделью, gates являются идеальным местом для реализации этой логики.

Давайте быстро посмотрим, как выглядит авторизация на основе gates:

1
...
2
...
3
Gate::define('update-post', function ($user, $post) {
4
  return $user->id == $post->user_id;
5
});
6
...
7
...

Вышеприведенный фрагмент определяет правило авторизации update-post, которое вы можете вызывать из любой точки приложения.

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

1
class PostPolicy
2
{
3
  public function view(User $user, Post $post) {}
4
  public function create(User $user) {}
5
  public function update(User $user, Post $post) {}
6
  public function delete(User $user, Post $post) {}
7
}

Как вы можете видеть, это довольно простой класс политики, который определяет авторизацию для действий CRUD модели Post.

Итак, это было введение в gates и политики в Laravel. В следующем разделе мы продолжим практическую демонстрацию каждого элемента.

Gates

В этом разделе мы увидим реальный пример, чтобы понять концепцию gates.

Чаще всего вы в конечном итоге смотрите на поставщика услуг Laravel, когда вам необходимо зарегистрировать компонент или услугу. Следуя этому соглашению, давайте продолжим и определим наши пользовательские gates в app/Providers/AuthServiceProvider.php, как показано в следующем фрагменте.

1
<?php
2
namespace App\Providers;
3
4
use Illuminate\Support\Facades\Gate;
5
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
6
use Illuminate\Http\Request;
7
8
class AuthServiceProvider extends ServiceProvider
9
{
10
  /**

11
   * The policy mappings for the application.

12
   *

13
   * @var array

14
   */
15
  protected $policies = [
16
    'App\Model' => 'App\Policies\ModelPolicy',
17
  ];
18
19
  /**

20
   * Register any authentication / authorization services.

21
   *

22
   * @return void

23
   */
24
  public function boot()
25
  {
26
    $this->registerPolicies();
27
    
28
    Gate::define('update-post', function ($user, $post) {
29
      return $user->id == $post->user_id;
30
    });
31
  }
32
}

В методе boot мы определили наш пользовательский элемент:

1
Gate::define('update-post', function ($user, $post) {
2
  return $user->id == $post->user_id;
3
});

При определении gates они принимают замыкание, которое возвращает либо TRUE, либо FALSE на основе логики авторизации, определенной в определении gates. Помимо функции замыкания, существуют и другие способы определения gates.

Например, следующее определение gates вызывает действие контроллера вместо функции замыкания.

1
Gate::define('update-post', 'ControllerName@MethodName');

Теперь давайте продолжим и добавим настраиваемый маршрут, чтобы мы могли продемонстрировать, как работает авторизация на основе gates. В файле маршрутов routes/web.php добавим следующий маршрут.

1
Route::get('service/post/gate', 'PostController@gate');

Давайте создадим соответствующий контроллер app/Http/Controllers/PostController.php.

1
<?php
2
namespace App\Http\Controllers;
3
4
use App\Http\Controllers\Controller;
5
use App\Post;
6
use Illuminate\Support\Facades\Gate;
7
8
class PostController extends Controller
9
{
10
  /* Make sure you don't user Gate and Policy altogether for the same Model/Resource */
11
  public function gate()
12
  {
13
    $post = Post::find(1);
14
15
    if (Gate::allows('update-post', $post)) {
16
      echo 'Allowed';
17
    } else {
18
      echo 'Not Allowed';
19
    }
20
    
21
    exit;
22
  }
23
}

В большинстве случаев вы можете использовать метод allows или denies фасада Gate для авторизации определенного действия. В нашем примере выше мы использовали метод allow, чтобы проверить, может ли текущий пользователь выполнить действие update-post.

Наиболее внимательные читатели заметили, что мы только передали второй аргумент $post в замыкание. Первый аргумент, текущий вошедший в систему пользователь, автоматически вводится фасадом Gate.

Так вот как вы должны использовать gates для авторизации действий в вашем приложении Laravel. Следующий раздел посвящен использованию политик, если вы хотите реализовать авторизацию для своих моделей.

Политики

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

В этом разделе мы создадим политику для модели Post, которая будет использоваться для авторизации всех действий CRUD. Я предполагаю, что вы уже внедрили модель Post в своем приложении; в противном случае что-то подобное будет сделано.

Команда Laravel artisan - ваш лучший друг, когда дело доходит до создания сгенерированного кода. Вы можете использовать следующую команду artisan для создания политики для модели Post.

1
$php artisan make:policy PostPolicy --model=Post

Как вы можете видеть, мы предоставили аргумент --model=Post, чтобы он создавал все методы CRUD. В отсутствие этого он создаст пустой класс политики. Вы можете найти вновь созданный класс политики внутри файла app/Policies/ PostPolicy.php.

Давайте заменим его на следующий код.

1
<?php
2
namespace App\Policies;
3
4
use App\User;
5
use App\Post;
6
use Illuminate\Auth\Access\HandlesAuthorization;
7
8
class PostPolicy
9
{
10
  use HandlesAuthorization;
11
12
  /**

13
   * Determine whether the user can view the post.

14
   *

15
   * @param  \App\User  $user

16
   * @param  \App\Post  $post

17
   * @return mixed

18
   */
19
  public function view(User $user, Post $post)
20
  {
21
    return TRUE;
22
  }
23
24
  /**

25
   * Determine whether the user can create posts.

26
   *

27
   * @param  \App\User  $user

28
   * @return mixed

29
   */
30
  public function create(User $user)
31
  {
32
    return $user->id > 0;
33
  }
34
35
  /**

36
   * Determine whether the user can update the post.

37
   *

38
   * @param  \App\User  $user

39
   * @param  \App\Post  $post

40
   * @return mixed

41
   */
42
  public function update(User $user, Post $post)
43
  {
44
    return $user->id == $post->user_id;
45
  }
46
47
  /**

48
   * Determine whether the user can delete the post.

49
   *

50
   * @param  \App\User  $user

51
   * @param  \App\Post  $post

52
   * @return mixed

53
   */
54
  public function delete(User $user, Post $post)
55
  {
56
    return $user->id == $post->user_id;
57
  }
58
}

Чтобы иметь возможность использовать наш класс Policy, нам необходимо зарегистрировать его с помощью поставщика услуг Laravel, как показано в следующем фрагменте.

1
<?php
2
namespace App\Providers;
3
4
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
5
use Illuminate\Http\Request;
6
use App\Post;
7
use App\Policies\PostPolicy;
8
9
class AuthServiceProvider extends ServiceProvider
10
{
11
  /**

12
   * The policy mappings for the application.

13
   *

14
   * @var array

15
   */
16
  protected $policies = [
17
    'App\Model' => 'App\Policies\ModelPolicy',
18
    Post::class => PostPolicy::class
19
  ];
20
21
  /**

22
   * Register any authentication / authorization services.

23
   *

24
   * @return void

25
   */
26
  public function boot()
27
  {
28
    $this->registerPolicies();
29
  }
30
}

Мы добавили отображение нашей политики в свойство $policy. Оно сообщает Laravel о вызове соответствующего метода политики для авторизации действия CRUD.

Вам также необходимо зарегистрировать политики, используя метод registerPolicies, как это было сделано в методе boot.

Двигаясь дальше, давайте создадим пару маршрутов в файле routes/web.php, чтобы мы могли протестировать наши методы политики.

1
Route::get('service/post/view', 'PostController@view');
2
Route::get('service/post/create', 'PostController@create');
3
Route::get('service/post/update', 'PostController@update');
4
Route::get('service/post/delete', 'PostController@delete');

Наконец, давайте создадим соответствующий контроллер в app/Http/Controllers/PostController.php.

1
<?php
2
namespace App\Http\Controllers;
3
4
use App\Http\Controllers\Controller;
5
use App\Post;
6
use Illuminate\Support\Facades\Auth;
7
8
class PostController extends Controller
9
{
10
  public function view()
11
  {
12
    // get current logged in user

13
    $user = Auth::user();
14
    
15
    // load post

16
    $post = Post::find(1);
17
    
18
    if ($user->can('view', $post)) {
19
      echo "Current logged in user is allowed to update the Post: {$post->id}";
20
    } else {
21
      echo 'Not Authorized.';
22
    }
23
  }
24
25
  public function create()
26
  {
27
    // get current logged in user

28
    $user = Auth::user();
29
30
    if ($user->can('create', Post::class)) {
31
      echo 'Current logged in user is allowed to create new posts.';
32
    } else {
33
      echo 'Not Authorized';
34
    }
35
36
    exit;
37
  }
38
39
  public function update()
40
  {
41
    // get current logged in user

42
    $user = Auth::user();
43
44
    // load post

45
    $post = Post::find(1);
46
47
    if ($user->can('update', $post)) {
48
      echo "Current logged in user is allowed to update the Post: {$post->id}";
49
    } else {
50
      echo 'Not Authorized.';
51
    }
52
  }
53
54
  public function delete()
55
  {
56
    // get current logged in user

57
    $user = Auth::user();
58
    
59
    // load post

60
    $post = Post::find(1);
61
    
62
    if ($user->can('delete', $post)) {
63
      echo "Current logged in user is allowed to delete the Post: {$post->id}";
64
    } else {
65
      echo 'Not Authorized.';
66
    }
67
  }
68
}

Существуют различные способы авторизации ваших действий с помощью политик. В нашем примере выше мы использовали модель User для авторизации наших действий модели Post.

Модель User предоставляет два полезных метода для авторизации - can и cant. Метод can используется для проверки того, может ли текущий пользователь выполнить определенное действие. И наоборот метод cant используется для определения неспособности выполнения действия.

Давайте рассмотрим фрагмент метода view из контроллера, чтобы узнать, что именно он делает.

1
public function view()
2
{
3
  // get current logged in user

4
  $user = Auth::user();
5
  
6
  // load post

7
  $post = Post::find(1);
8
  
9
  if ($user->can('view', $post)) {
10
    echo "Current logged in user is allowed to update the Post: {$post->id}";
11
  } else {
12
    echo 'Not Authorized.';
13
  }
14
}

Во-первых, мы загружаем зарегистрированного пользователя, который дает нам объект модели пользователя. Затем мы загружаем пример сообщения с использованием модели Post.

Двигаясь вперед, мы использовали метод can модели User для авторизации действия view модели Post. Первый аргумент метода can - это имя действия, которое вы хотите разрешить, а второй аргумент - это объект модели, на который вы хотите получить разрешение.

Это была демонстрация использования модели User для авторизации действий с использованием политик. В качестве альтернативы вы также можете использовать Controller Helper, если вы находитесь в контроллере, разрешив определенное действие.

1

2
$this->authorize('view', $post);
3

Как вы можете видеть, вам не нужно загружать модель User, если вы используете Controller Helper.

Таким образом, это была концепция политики, и она очень удобная при авторизации модели или ресурса, поскольку она позволяет группировать логику авторизации в одном месте.

Просто убедитесь, что вы не используете gates и политики в целом для тех же действий модели, иначе это создаст проблемы. Это все с моей стороны на сегодня!

Заключение

Сегодня мы изучали авторизацию Laravel, которая заняла центральное место в моей статье. В начале статьи я представил основные элементы авторизации, gates и политик Laravel.

После этого мы прошли через создание пользовательских gates и политик, чтобы увидеть, как это работает в реальном приложении. Надеюсь, вам понравилась статья и вы выучили что-то полезное в контексте Laravel.

Для тех из вас, кто только начинает работать с Laravel или хочет расширить свои знания, создать сайт или приложение, у нас есть множество вещей, которые вы можете изучить на Envato Market.

Как всегда, я хотел бы услышать от вас в виде комментариев, используя приведенный ниже канал!