Статьи

Ворота и политика в Ларавеле

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

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

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

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

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

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

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

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

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

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

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

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

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

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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<?php
namespace App\Providers;
 
use Illuminate\Support\Facades\Gate;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Illuminate\Http\Request;
 
class AuthServiceProvider extends ServiceProvider
{
  /**
   * The policy mappings for the application.
   *
   * @var array
   */
  protected $policies = [
    ‘App\Model’ => ‘App\Policies\ModelPolicy’,
  ];
 
  /**
   * 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;
    });
  }
}

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

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

При определении шлюза требуется закрытие, которое возвращает либо ИСТИНА, либо ЛОЖЬ на основе логики авторизации, определенной в определении шлюза. Помимо функции закрытия, есть и другие способы определения ворот.

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

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

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

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

Давайте также создадим связанный файл контроллера app/Http/Controllers/PostController.php .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?php
namespace App\Http\Controllers;
 
use App\Http\Controllers\Controller;
use App\Post;
use Illuminate\Support\Facades\Gate;
 
class PostController extends Controller
{
  /* Make sure you don’t user Gate and Policy altogether for the same Model/Resource */
  public function gate()
  {
    $post = Post::find(1);
 
    if (Gate::allows(‘update-post’, $post)) {
      echo ‘Allowed’;
    } else {
      echo ‘Not Allowed’;
    }
     
    exit;
  }
}

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

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

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

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

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

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

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

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

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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
<?php
namespace App\Policies;
 
use App\User;
use App\Post;
use Illuminate\Auth\Access\HandlesAuthorization;
 
class PostPolicy
{
  use HandlesAuthorization;
 
  /**
   * Determine whether the user can view the post.
   *
   * @param \App\User $user
   * @param \App\Post $post
   * @return mixed
   */
  public function view(User $user, Post $post)
  {
    return TRUE;
  }
 
  /**
   * Determine whether the user can create posts.
   *
   * @param \App\User $user
   * @return mixed
   */
  public function create(User $user)
  {
    return $user->id > 0;
  }
 
  /**
   * Determine whether the user can update the post.
   *
   * @param \App\User $user
   * @param \App\Post $post
   * @return mixed
   */
  public function update(User $user, Post $post)
  {
    return $user->id == $post->user_id;
  }
 
  /**
   * Determine whether the user can delete the post.
   *
   * @param \App\User $user
   * @param \App\Post $post
   * @return mixed
   */
  public function delete(User $user, Post $post)
  {
    return $user->id == $post->user_id;
  }
}

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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<?php
namespace App\Providers;
 
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Illuminate\Http\Request;
use App\Post;
use App\Policies\PostPolicy;
 
class AuthServiceProvider extends ServiceProvider
{
  /**
   * The policy mappings for the application.
   *
   * @var array
   */
  protected $policies = [
    ‘App\Model’ => ‘App\Policies\ModelPolicy’,
    Post::class => PostPolicy::class
  ];
 
  /**
   * Register any authentication / authorization services.
   *
   * @return void
   */
  public function boot()
  {
    $this->registerPolicies();
  }
}

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

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

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

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

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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
<?php
namespace App\Http\Controllers;
 
use App\Http\Controllers\Controller;
use App\Post;
use Illuminate\Support\Facades\Auth;
 
class PostController extends Controller
{
  public function view()
  {
    // get current logged in user
    $user = Auth::user();
     
    // load post
    $post = Post::find(1);
     
    if ($user->can(‘view’, $post)) {
      echo «Current logged in user is allowed to update the Post: {$post->id}»;
    } else {
      echo ‘Not Authorized.’;
    }
  }
 
  public function create()
  {
    // get current logged in user
    $user = Auth::user();
 
    if ($user->can(‘create’, Post::class)) {
      echo ‘Current logged in user is allowed to create new posts.’;
    } else {
      echo ‘Not Authorized’;
    }
 
    exit;
  }
 
  public function update()
  {
    // get current logged in user
    $user = Auth::user();
 
    // load post
    $post = Post::find(1);
 
    if ($user->can(‘update’, $post)) {
      echo «Current logged in user is allowed to update the Post: {$post->id}»;
    } else {
      echo ‘Not Authorized.’;
    }
  }
 
  public function delete()
  {
    // get current logged in user
    $user = Auth::user();
     
    // load post
    $post = Post::find(1);
     
    if ($user->can(‘delete’, $post)) {
      echo «Current logged in user is allowed to delete the Post: {$post->id}»;
    } else {
      echo ‘Not Authorized.’;
    }
  }
}

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

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

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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
public function view()
{
  // get current logged in user
  $user = Auth::user();
   
  // load post
  $post = Post::find(1);
   
  if ($user->can(‘view’, $post)) {
    echo «Current logged in user is allowed to update the Post: {$post->id}»;
  } else {
    echo ‘Not Authorized.’;
  }
}

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

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

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

1
2
3
$this->authorize(‘view’, $post);

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

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

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

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

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

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

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