Хочу разобрать случай когда нужно выставлять права определенному пользователю. Например, Вы разрабатываете 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.
Если есть вопросы задавайте в комментарии