Sistema avançado de autorização de recursos no Laravel. Parte 1. Modelo, Controlador

Introdução


Olá queridos Khabrovchans.
No decorrer do meu trabalho na plataforma da API, passei muito tempo procurando a maneira certa de autorizar ações do usuário. A tarefa foi definida da seguinte forma - para criar um sistema bastante extenso de controle de acesso e ações.
Ao mesmo tempo, a maioria deles usa CRUD regular, mas outras ações do controlador precisam ser autorizadas.
Portanto, é necessário criar um sistema simples e ao mesmo tempo eficaz e flexível. Havia muitos cones, porque nesses artigos eu decidi demonstrar uma versão um pouco simplificada do que fiz.


Gostaria de acrescentar separadamente - o material foi projetado para a prática de programadores e será difícil para um iniciante entender. Este artigo não agendará a instalação do projeto e as configurações para conectar-se ao banco de dados. Tudo isso você pode encontrar facilmente na Internet.



Parte 1. Modelo, Controladores


Portanto, a tarefa: existem muitos modelos, cujo número pode aumentar e diminuir durante o desenvolvimento do projeto.
As ações em cada um deles devem ser autorizadas por funções.
Existem ações simples, como CRUD, e outras adicionais (por exemplo, importação, exportação ).
É necessário simplificar o trabalho do desenvolvedor (para o seu amado), tanto quanto possível, para introduzir modelos e métodos adicionais a eles.
O artigo fornece um exemplo para um aplicativo Api, mas a solução é adequada não apenas para isso.


Modelo


Post. ( ) app.
app/Models Posts. ( , -).
. :


    php artisan make:model Models/Post --api --migration
    php artisan migrate

: , . , .



PostController CRUD
Controller.
ModelController Controller , , PostController.
PostControllerimport() export(Post $post).
, .



Laravel Illuminate\Foundation\Auth\Access\AuthorizesRequests.
App\Http\Controllers\Controller ModelController. Controller , .
authorizeResource($model).
, (Middleware) .
:


    can:viewAny,App\Models\Post
    can:view,post
    can:update,post

, , — :


  1. viewAny view apiResource
  2. , — .

:


. resourceAbilityMap() .


<?php
protected function resourceAbilityMap()
{
    return [
        'index' => 'viewAny',
        'show' => 'view',
        'create' => 'create',
        'store' => 'create',
        'edit' => 'update',
        'update' => 'update',
        'destroy' => 'delete',
    ];
}

. Laravel . , . index() , show(Post $post) . resourceMethodsWithoutModels()


<?php
protected function resourceMethodsWithoutModels()
{
    return ['index', 'create', 'store'];
}


(ModelController)

app/Http/Controllers ModelController. :


  • $guardedMethods « » => « ».
    (Policy) , , (Gate). .
  • $methodsWithoutModels .
  • getModelClass() .
    .
  • authorizeResource($this->getModelClass()) . ( (Route), )
  • resourceAbilityMap() resourceMethodsWithoutModels() , , .

<?php

namespace App\Http\Controllers;

abstract class ModelController extends Controller
{
    /** @var array 'method' => 'policy'*/
    protected $guardedMethods = [];

    protected $methodsWithoutModels = [];

    protected abstract function getModelClass(): string;

    public function __construct()
    {
        $this->authorizeResource($this->getModelClass());
    }

    protected function resourceAbilityMap()
    {
        $base = parent::resourceAbilityMap();

        return array_merge($base, $this->guardedMethods);
    }

    protected function resourceMethodsWithoutModels()
    {
        $base = parent::resourceMethodsWithoutModels();

        return array_merge($base, $this->methodsWithoutModels);
    }
}

(PostController)

:


  • getModelClass() .
  • $methodsWithoutModels « » => « » . . , =. , , .
  • $methodsWithoutModels , . import
  • — , . — .

<?php

namespace App\Http\Controllers;

use App\Models\Post;
use Illuminate\Http\Request;

class PostController extends ModelController
{
    /** @var array 'method' => 'policy'*/
    protected $guardedMethods = [
        'export' => 'export',
        'import' => 'import',
    ];

    protected $methodsWithoutModels = ['import'];

    protected function getModelClass(): string
    {
        return Post::class;
    }

    public function index()
    { /**     */ }

    public function store(Request $request)
    { /**    */ }

    public function show(Post $post)
    { /**    */ }

    public function update(Request $request, Post $post)
    { /**    */ }

    public function destroy(Post $post)
    { /**    */ }

    public function import()
    { /**     */ }

    public function export(Post $post)
    { /**    */ }
}

(Routes)


.
'routes/api.php' ( 'routes/web.php', ) .
, , .
— ( ) , Route::apiResource('posts', 'PostController'). Laravel. .
— 'auth:api'. , .


<?php

use App\Http\Controllers\PostController;
use Illuminate\Support\Facades\Route;

Route::group(['middleware' => ['auth:api']], static function () {
    Route::post('posts/import', 'PostController@import')->name('posts.import');
    Route::get('posts/{post}/export', 'PostController@export')->name('posts.export');
    Route::apiResource('posts', 'PostController');
});

. :


php artisan route:list

— ( )


+-----------------------+---------------------------+-------------------------------+
|URI                    |Action                     |Middleware                     |
+-----------------------+---------------------------+-------------------------------+
|api/posts              |...\PostController@index   |...,can:viewAny,App\Models\Post|
|api/posts              |...\PostController@store   |...,can:create,App\Models\Post |
|api/posts/import       |...\PostController@import  |...,can:import,App\Models\Post |
|api/posts/{post}       |...\PostController@show    |...,can:view,post              |
|api/posts/{post}       |...\PostController@update  |...,can:update,post            |
| api / posts / {post} | ... \ PostController @ destroy | ..., pode: excluir, publicar |
| api / posts / {post} / export | ... \ PostController @ export | ..., pode: exportar, publicar |
+ ----------------------- + ------------------------- - + ------------------------------- +



O próximo passo é configurar o link Gate (Gate) <-> Policy. Mas mais sobre isso na segunda parte .


All Articles