Introdução
Olá querido Khabrovchane.
Continuo minha série de artigos sobre autorização avançada de recursos no Laravel. Para entender melhor o que será discutido neste artigo, você precisa ler a primeira parte .
Para começar, repetirei brevemente a afirmação do problema: Há um grande número de modelos. É necessário projetar um sistema flexível e facilmente extensível para autorizar ações do usuário, dependendo de sua função.
Nesta parte, falaremos sobre a configuração do link Policy <=> Gateway. E também é proposta uma das opções para gravar direitos de usuário no banco de dados.
E, é claro, vou esclarecer imediatamente que o material foi projetado para a prática de programadores e será difícil para um desenvolvedor iniciante entender.
Parte 3. Políticas, Gateways
Parte teórica
Muito material na Internet pode ser encontrado no tópico - “O que escolher Policy ou Gate ?”. Por um certo tempo, também cheguei a um erro semelhante, que você precisa escolher. Mas, no final, cheguei à conclusão - esses são dois elos da mesma cadeia, que são mais efetivamente usados em conjunto.
No Laravel, existem duas direções principais para determinar esse pacote - manual e automático. Não considerarei manual, pois o suporte a esse tipo de pacote exigirá esforços desproporcionalmente mais do programador do que a configuração automática.
— , () . (Gate) — . — , . , . , app. . app/Models.
Gate::guessPolicyNamesUsing('callback'). , boot() App\Providers\AuthServiceProvider( ).
Gate
(callback), guessPolicyNamesUsing() , . . : Policy . , , Laravel ( ). SuperAdmin , , — super-admin . — .
PHP 7.4 . 7.4 .
<?php
namespace App\Providers;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Gate;
class AuthServiceProvider extends ServiceProvider
{
public function boot()
{
$this->defineSuperAdmin();
$this->defineAutoDiscover();
}
private function defineAutoDiscover()
{
Gate::guessPolicyNamesUsing(function ($class) {
return str_replace("\\Models\\", "\\Policies\\" , $class) . 'Policy';
});
}
private function defineSuperAdmin()
{
Gate::before(function($user) {
return $user->hasRole('super-admin') ? true : null;
});
}
}
Policy
, , . . :
php artisan make:policy PostPolicy --model=Models/Post
. . , DRY,- , . , . , getModelClass() . , ( ). . (import export — )
<?php
protected function resourceAbilityMap()
{
return [
'index' => 'viewAny',
'show' => 'view',
'create' => 'create',
'store' => 'create',
'edit' => 'update',
'update' => 'update',
'destroy' => 'delete',
'import' => 'import',
'export' => 'export',
];
}
— , . , . . Spatie. laravel-permission. , — , , . , , . — , $user->can() $user->hasRole(), Spatie\Permission\Traits\HasRoles
(Models\User)
<?php
namespace App\Models;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Spatie\Permission\Traits\HasRoles;
class User extends Authenticatable
{
use Notifiable;
use HasRoles;
}
, (Admin User, ) — HasRoles, .
.
(ModelPolicy)
<?php
namespace App\Policies;
use App\Models\User;
use App\Models\Post;
use Illuminate\Auth\Access\HandlesAuthorization;
use Illuminate\Database\Eloquent\Model;
abstract class ModelPolicy
{
use HandlesAuthorization;
abstract protected function getModelClass(): string;
public function viewAny(User $user)
{
return $user->can('view-any-' . $this->getModelClass());
}
public function view(User $user, Post $model)
{
return $user->can('view-' . $this->getModelClass());
}
public function create(User $user)
{
return $user->can('create-' . $this->getModelClass());
}
public function update(User $user, Post $model)
{
return $user->can('update-' . $this->getModelClass());
}
public function delete(User $user, Post $model)
{
return $user->can('delete-' . $this->getModelClass());
}
}
$user->can('ability') . . ''-' ', — ( ). (SoftDelete). , .
. Post getResourceName() .
(PostPolicy)
<?php
namespace App\Policies;
use App\Models\Post;
use App\Models\User;
use Illuminate\Database\Eloquent\Model;
class PostPolicy extends ModelPolicy
{
protected function getModelClass(): string
{
return Post::class;
}
public function import(User $user)
{
return $user->can('import-' . $this->getModelClass());
}
public function export(User $user, Post $model)
{
return $user->can('export-' . $this->getModelClass());
}
}
, import() , . — . . , .
, , . .
4. (Seeding)
, . .
spatie/laravel-permission, . .
:
composer require spatie/laravel-permission
php artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider"
(seeder)
php artisan make:seeder PermissionsSeeder
run() database/seeds/DatabaseSeeder.php. PermissionsSeeder .
(DatabaseSeeder)
<?php
use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder
{
public function run()
{
$this->call(PermissionsSeeder::class);
}
}
, — PermissionsSeeder. database/data php . :
role => model => action
// (permissions_roles.php)
<?php
return [
'admin' => [
'App\\Models\\Post' => [
'view',
'view-any',
'create',
'update',
'delete',
'import',
'export',
],
],
'App\\Models\\Post' => [
'post' => [
'view',
'view-any',
],
],
];
. , , — .
(PermissionsSeeder)
<?php
use Illuminate\Database\Seeder;
use Spatie\Permission\Models\Permission;
use Spatie\Permission\Models\Role;
class PermissionsSeeder extends Seeder
{
private $data = [];
public function run()
{
$this->loadData();
$this->seedRoles();
}
public function loadData(): void
{
$this->data = require_once database_path("data/permissions_roles.php");
}
private function seedRoles(): void
{
Role::create(['name' => 'super-admin', 'guard_name' => 'api']);
foreach ($this->data as $roleName => $perms) {
$role = Role::create(['name' => $roleName, 'guard_name' => 'api']);
$this->seedRolePermissions($role, $perms);
}
}
private function seedRolePermissions(Role $role, array $modelPermissions): void
{
foreach ($modelPermissions as $model => $perms) {
$buildedPerms = collect($perms)
->crossJoin($model)
->map(function ($item) {
$perm = implode('-', $item);
Permission::findOrCreate($perm, 'api');
return $perm;
})->toArray();
$role->givePermissionTo($buildedPerms);
}
}
}
, - . , , . , , .
, :
- run() .
- loadData() database/data $data
- seedRoles() . , $data, . 'super-admin' , , .. ( AuthServiceProvider).
- seedRolePermissions() , , «» , (permission). . () — findOrCreate(), laravel-permissions. , , .
, . :
php artisan migrate --seed
. ! , :
- (Model).
- (Controller) ModelController.
- (Policy) ModelPolicy.
- .
, (. 1) (. ).
É tudo por agora. Espero que este artigo tenha sido útil. E se alguém estiver interessado em ajustar ainda mais os direitos e restrições dos usuários, ou seja, o direito do usuário de assistir / alterar um atributo específico do modelo - isso é
discutido na terceira parte .