Хочу разобрать случай когда нужно выставлять права определенному пользователю. Например, Вы разрабатываете CRM-систему у владельца компании есть сотрудники которые имеют доступ к системе и Вам необходимо чтобы несколько сотрудников выполняли разные функции или запретить экспорт базы данных клиентов.
Подготовка базы данных.
Создание миграции.
php artisan make:migration create_permissions_table --create=permissions
<?php use Illuminate\Support\Facades\Schema; use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class CreatePermissionsTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('permissions', function (Blueprint $table) { $table->increments('id'); // идентификатор $table->string('name')->unique(); // имя на анг. $table->integer('parent'); // родитель $table->string('display_name')->nullable(); // Отображаемое имя $table->string('description')->nullable(); // описание $table->index('parent'); // присваиваемым индекс полю родитель $table->timestamps(); }); Schema::create('permission_user', function (Blueprint $table) { $table->integer('permission_id')->unsigned(); // id права $table->integer('user_id')->unsigned(); // id пользователя $table->foreign('permission_id')->references('id')->on('permissions') // устанавливаем зависимости полей ->onUpdate('cascade')->onDelete('cascade'); $table->foreign('user_id')->references('id')->on('users') ->onUpdate('cascade')->onDelete('cascade'); $table->primary(['permission_id', 'user_id']); // ключи }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('permissions'); Schema::dropIfExists('permission_user'); } }
Содержимое миграции.
Таблица «permissions» будет содержать набор прав пользователей, «permissions_user» права пользователя.
Выполняем миграцию php artisan migrate
Создаем модель.
php artisan make:model /Models/Permission
Содержимое модели ниже. Связь с таблицей пользователи многое ко многим.
<?php namespace App\Models; use Illuminate\Database\Eloquent\Model; use Illuminate\Support\Facades\Cookie; class Permission extends Model { protected $table = 'permissions'; protected $fillable = [ 'name', 'parent', 'display_name', 'description' ]; /** * Пользователи, которые принадлежат права. */ public function users() { return $this->belongsToMany('App\Models\User', 'permission_user', 'permission_id', 'user_id'); } }
Seed.
Сразу же для удобства создадим наполнения БД начальными данными(seeding). Эти классы хранятся в app/database/seeds
Создадим файл PermissionsTableSeeder.php и записываем необходимый набор прав.
У меня такой получился такой набор.
<?php use Illuminate\Database\Seeder; use App\Models\Permission; class PermissionTableSeeder extends Seeder { /** * Run the database seeds. * * @return void */ public function run() { $permission = [ /* client */ [ 'name' => 'client-list', 'parent_id' => '0', 'display_name' => 'Просмотр клиента', 'description' => '' ], /* master */ [ 'name' => 'master-list', 'parent_id' => '0', 'display_name' => 'Просмотр мастеров', 'description' => '' ], /* personal */ [ 'name' => 'personal-list', 'parent_id' => '0', 'display_name' => 'Просмотр персонала', 'description' => '' ], /* record */ [ 'name' => 'record-list', 'parent_id' => '0', 'display_name' => 'Работа с записями', 'description' => '' ], /* company */ [ 'name' => 'company-list', 'parent_id' => '0', 'display_name' => 'Просмотр списка компаний', 'description' => '' ], /* products */ [ 'name' => 'product-management', 'parent_id' => '0', 'display_name' => 'Управление складом', 'description' => '' ], /* metric */ [ 'name' => 'metric-list', 'parent_id' => '0', 'display_name' => 'Просмотр статистики', 'description' => '' ], [ 'name' => 'client-create', 'parent_id' => '1', 'display_name' => 'Создание новых клиентов', 'description' => '' ], [ 'name' => 'client-edit', 'parent_id' => '1', 'display_name' => 'Изменение данных клиента', 'description' => '' ], [ 'name' => 'client-copy', 'parent_id' => '1', 'display_name' => 'Выгрузка клиентской БД', 'description' => '' ], [ 'name' => 'client-delete', 'parent_id' => '1', 'display_name' => 'Удаление клиента', 'description' => '' ], /* master */ [ 'name' => 'master-create', 'parent_id' => '2', 'display_name' => 'Создание мастера', 'description' => '' ], [ 'name' => 'master-edit', 'parent_id' => '2', 'display_name' => 'Изменение данных мастера', 'description' => '' ], [ 'name' => 'master-delete', 'parent_id' => '2', 'display_name' => 'Удаление мастера', 'description' => '' ], /* personal */ [ 'name' => 'personal-confirm', 'parent_id' => '3', 'display_name' => 'Подтвержать регистрацию', 'description' => '' ], [ 'name' => 'personal-edit', 'parent_id' => '3', 'display_name' => 'Изменение данных персонала', 'description' => '' ], [ 'name' => 'personal-delete', 'parent_id' => '3', 'display_name' => 'Удаление персонала', 'description' => '' ], /* record */ [ 'name' => 'record-delete', 'parent_id' => '4', 'display_name' => 'Удаление записей', 'description' => ' ' ], /* company */ [ 'name' => 'company-create', 'parent_id' => '5', 'display_name' => 'Создание компании', 'description' => '' ], [ 'name' => 'company-edit', 'parent_id' => '5', 'display_name' => 'Правка информации о компании', 'description' => '' ], [ 'name' => 'company-delete', 'parent_id' => '5', 'display_name' => 'Удаление информации о компании', 'description' => '' ], /* products */ [ 'name' => 'product-category', 'parent_id' => '6', 'display_name' => 'Работа с категориями', 'description' => '' ], [ 'name' => 'product-provider', 'parent_id' => '6', 'display_name' => 'Работа с поставщиками', 'description' => '' ], [ 'name' => 'product-sale', 'parent_id' => '6', 'display_name' => 'Продажа товара', 'description' => '' ], [ 'name' => 'product-history-sale', 'parent_id' => '6', 'display_name' => 'Просмотр истории продаж', 'description' => '' ], [ 'name' => 'product-history', 'parent_id' => '6', 'display_name' => 'Просмотр истории', 'description' => '' ], [ 'name' => 'product-delete', 'parent_id' => '6', 'display_name' => 'Удаление товаров', 'description' => '' ] ]; foreach ($permission as $key => $value) { Permission::create($value); } } }
Запускаем сид php artisan db:seed —class=PermissionsTableSeeder
Теперь нужно написать проверку на наличие прав получения, название права и связь с таблицей прав.
В модели User.php
/** * Проверка имеет ли пользователь определенную роль * @param $check * @return boolean */ public function hasPermission($check) { return in_array($check, array_pluck($this->permissions->toArray(), 'name')); } /** * Получает название права * @param $name * @return mixed */ public function getPermissionDisplayName($name) { return DB::table('permissions')->where('name', $name)->first()->display_name; } /** * Функция для получение прав. * @return boolean **/ public function permissions() { return $this->belongsToMany('App\Models\Permission', 'permission_user', 'user_id', 'permission_id'); }
Создание посредника.
Проверка прав у пользователей будет через посредника(middleware).
php artisan make:middleware PermissionMiddleware
<?php namespace App\Http\Middleware; use Closure; class PermissionMiddleware { /** * Handle an incoming request. * * @param \Illuminate\Http\Request $request * @param \Closure $next * @param $permission * @return mixed */ public function handle($request, Closure $next, $permission) { if (!$request->user()->hasPermission($permission)) { $name = $request->user()->getPermissionDisplayName($permission); return redirect('/')->with('error', 'Не достаточно прав! Для операции: "' . $name . '"'); } return $next($request); } }
После создание посредника нужно зарегистрировать его. Переходим в файл Kernel.php и дописываем строку в массив $routeMiddleware
protected $routeMiddleware = [ *** 'permission' => \App\Http\Middleware\PermissionMiddleware::class, *** ];
Использование.
Теперь в роуторе можно использовать права. Например, для работы с клиентам.
/* Работа с клиентами */ Route::get('clients', ['as' => 'clients.index', 'uses' => 'ClientsController@index', 'middleware' => ['permission:client-list']]); Route::post('clients/create', ['as' => 'clients.store', 'uses' => 'ClientsController@store', 'middleware' => ['permission:client-create']]); Route::post('clients/create/ajax', ['as' => 'clients.store.ajax', 'uses' => 'ClientsController@storeAjax', 'middleware' => ['permission:client-create']]); Route::get('clients/{id}', ['as' => 'clients.show', 'uses' => 'ClientsController@show', 'middleware' => ['permission:client-list']]); Route::patch('clients/{id}', ['as' => 'clients.update', 'uses' => 'ClientsController@update', 'middleware' => ['permission:client-edit']]); Route::delete('clients/{id}', ['as' => 'clients.destroy', 'uses' => 'ClientsController@destroy', 'middleware' => ['permission:client-delete']]);
Со стороны UI не охота было бы видеть кнопку удалить по которой нельзя нажать. Выход из этого такой.
Переходим в файл шаблона и прописываем такую конструкцию на кнопку или на любой другой элемент и если у пользователя есть права, то он увидит содержимое.
@if (Auth::user()->hasPermission('client-delete')) // other code @endif
По присваиванию прав будет отдельная статья. В ней будет использоваться jQuery плагин jsTree.
Если есть вопросы задавайте в комментарии