• Время чтения ~9 мин
  • 10.09.2023

Есть куча пакетов для Laravel для управления ролями пользователей и разрешениями. Наиболее популярными из них являются роли и разрешения Spaties, а также роли и разрешения Laratrust. Мы можем легко управлять ролями и разрешениями в Laravel с помощью этих пакетов. Но в этом уроке наша цель состоит в том, чтобы создать систему ролей и разрешений без каких-либо пакетов. Поэтому мы не собираемся использовать какой-либо тип пакета для создания этой системы ролей и разрешений Laravel 10.

В этом уроке я создам полный Laravel 10 ролей и разрешений без пакета. Чтобы создать эти системы ролей и разрешений Laravel, нам нужно сначала понять сценарий ролей и разрешений для пользователя. Итак , что мы собираемся сделать в этом уроке, давайте посмотрим на сценарий:

  • У пользователя может быть роль
  • Роль может иметь множество разрешений
  • У пользователей может быть несколько ролей

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

laravel-custom-role-and-permission-inplementation

Давайте посмотрим на изображение панели мониторинга предварительного просмотра этой роли и разрешений Laravel 10:Вошел в систему как роль пользователя:Шаг 1: Загрузите свежийLaravel На первом шаге Laravel 10 ролей и разрешений без пакета загрузите новое приложение Laravel

laravel-10-roles-and-permissions-without-package

с помощью следующей команды:Шаг 2: 

laravel-10-roles-and-permissions-tutorial

composer create-project laravel/laravel example-app

Создайте аутентификацию Нам нужна аутентификация.

Чтобы создать простую аутентификацию начальной загрузки, выполните следующую команду:Шаг 3: Подключение базы данных Теперьподключите базу данных

composer require laravel/ui --dev
php artisan ui bootstrap --auth
npm install
npm run dev

, потому что нам нужна миграция для этого Laravel роли и разрешения пример:.env

Шаг 4:

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=root
DB_PASSWORD=password

Создание модели

Нам нужна модель для создания ролей и разрешений пользователей. Итак, давайте создадим нашу модель, используя приведенную ниже команду, чтобы выполнить роли и разрешения Laravel 10 без пакета.

php artisan make:model Permission -m
php artisan make:model Role -m

Теперь обновите файл миграции, например:Таблицы миграций для разрешений:

<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::create('roles', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->timestamps();
        });
    }
    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::dropIfExists('roles');
    }
};

<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::create('permissions', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->timestamps();
        });
    }
    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::dropIfExists('permissions');
    }
};

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

<?php
use App\Models\Permission;
use App\Models\User;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::create('users_permissions', function (Blueprint $table) {
            $table->foreignIdFor(User::class)->constrained()->cascadeOnDelete();
            $table->foreignIdFor(Permission::class)->constrained()->cascadeOnDelete();
        });
    }
    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::dropIfExists('users_permissions');
    }
};

Теперь давайте создадим сводную таблицуusers_permissions для 

<?php
use App\Models\Role;
use App\Models\User;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::create('users_roles', function (Blueprint $table) {
            $table->foreignIdFor(User::class)->constrained()->cascadeOnDelete();
            $table->foreignIdFor(Role::class)->constrained()->cascadeOnDelete();
        });
    }
    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::dropIfExists('users_roles');
    }
};

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

php artisan make:migration create_roles_permissions_table --create=roles_permissions

Теперь обновите like:Теперь выполните следующую команду, чтобы создать миграцию

<?php
use App\Models\Permission;
use App\Models\Role;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::create('roles_permissions', function (Blueprint $table) {
            $table->foreignIdFor(Role::class)->constrained()->cascadeOnDelete();
            $table->foreignIdFor(Permission::class)->constrained()->cascadeOnDelete();
        });
    }
    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::dropIfExists('roles_permissions');
    }
};

Шаг 5: Обновитемодель с помощью отношений Теперь обновите ролевую модель с помощью такой связи:app\Models\Role.php Теперь обновите roles_permissions модель разрешений с помощью

php artisan migrate

такой связи:

Шаг 6: 

<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Role extends Model
{
    use HasFactory;
    public function permissions()
    {
        return $this->belongsToMany(Permission::class, 'roles_permissions');
    }
    public function users()
    {
        return $this->belongsToMany(User::class, 'users_roles');
    }
}

<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Permission extends Model
{
    use HasFactory;
    public function roles()
    {
        return $this->belongsToMany(Role::class, 'roles_permissions');
    }
    public function users()
    {
        return $this->belongsToMany(User::class, 'users_permissions');
    }
}

Создайте характеристику службы

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

App\Traits\HasPermissionsTrait.php

<?php
namespace App\Traits;
use App\Models\Role;
use App\Models\Permission;
trait HasPermissionsTrait
{
    public function givePermissionsTo(...$permissions)
    {
        $permissions = $this->getAllPermissions($permissions);
        if ($permissions === null) {
            return $this;
        }
        $this->permissions()->saveMany($permissions);
        return $this;
    }
    public function withdrawPermissionsTo(...$permissions)
    {
        $permissions = $this->getAllPermissions($permissions);
        $this->permissions()->detach($permissions);
        return $this;
    }
    public function refreshPermissions(...$permissions)
    {
        $this->permissions()->detach();
        return $this->givePermissionsTo($permissions);
    }
    public function hasPermissionTo($permission)
    {
        return $this->hasPermissionThroughRole($permission) || $this->hasPermission($permission);
    }
    public function hasPermissionThroughRole($permission)
    {
        foreach($permission->roles as $role) {
            if ($this->roles->contains($role)) {
                return true;
            }
        }
        return false;
    }
    public function hasRole(...$roles)
    {
        foreach($roles as $role) {
            if ($this->roles->contains('name', $role)) {
                return true;
            }
        }
        return false;
    }
    public function roles()
    {
        return $this->belongsToMany(Role::class, 'users_roles');
    }
    public function permissions()
    {
        return $this->belongsToMany(Permission::class, 'users_permissions');
    }
    protected function hasPermission($permission)
    {
        return (bool) $this->permissions->where('name', $permission->name)->count();
    }
    protected function getAllPermissions(array $permissions)
    {
        return Permission::whereIn('name', $permissions)->get();
    }
}

Теперь обновите модель User с помощью этой черты.

app\Models\User.php

<?php
namespace App\Models;
use App\Traits\HasPermissionsTrait;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;
class User extends Authenticatable
{
    use HasApiTokens,
        HasFactory,
        Notifiable,
        HasPermissionsTrait;
    protected $fillable = [
        'name',
        'email',
        'password',
    ];
    protected $hidden = [
        'password',
        'remember_token',
    ];
    protected $casts = [
        'email_verified_at' => 'datetime',
        'password' => 'hashed',
    ];
}

Шаг 7. Создание директивы

Role BladeТеперь на этот раз мы создадим директиву @role() blade. Поэтому обновите поставщика службы приложений следующим образом:Шаг 8:

Шаг 8:

<?php
namespace App\Providers;
use App\Models\Permission;
use Illuminate\Support\Facades\Gate;
use Illuminate\Support\Facades\Blade;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
    public function register(): void
    {
    }
    public function boot(): void
    {
        try {
            Permission::get()->map(function ($permission) {
                Gate::define($permission->name, function ($user) use ($permission) {
                    return $user->hasPermissionTo($permission);
                });
            });
        } catch (\Exception $e) {
            report($e);
        }
        Blade::directive('role', function ($role) {
            return "<?php if(auth()->check() && auth()->user()->hasRole({$role})) : ?>";
        });
        Blade::directive('endrole', function ($role) {
            return "<?php endif; ?>";
        });
    }
}

Создайте сеялку

Теперь на этом шаге мы создадим некоторые фиктивные данные для создания ролей и разрешений для пользователей. Итак, выполните приведенную ниже команду:Теперь обновите его следующим образом:База данных\Seeders\RoleSeeder.php Теперь обновите сеялку базы данных следующим образом:

php artisan make:seeder RoleSeeder

<?php
namespace Database\Seeders;
use App\Models\Role;
use App\Models\User;
use App\Models\Permission;
use Illuminate\Database\Seeder;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
class RoleSeeder extends Seeder
{
    public function run(): void
    {
        $permission = new Permission();
        $permission->name = 'create-post';
        $permission->save();
        $role = new Role();
        $role->name = 'admin';
        $role->save();
        $role->permissions()->attach($permission);
        $permission->roles()->attach($role);
        $permission = new Permission();
        $permission->name = 'create-user';
        $permission->save();
        $role = new Role();
        $role->name = 'user';
        $role->save();
        $role->permissions()->attach($permission);
        $permission->roles()->attach($role);
        $admin = Role::where('name', 'admin')->first();
        $userRole = Role::where('name', 'user')->first();
        $create_post = Permission::where('name', 'create-post')->first();
        $create_user = Permission::where('name', 'create-user')->first();
        $admin = new User();
        $admin->name = 'Admin';
        $admin->email = '[email protected]';
        $admin->password = bcrypt('admin');
        $admin->save();
        $admin->roles()->attach($admin);
        $admin->permissions()->attach($create_post);
        $user = new User();
        $user->name = 'User';
        $user->email = '[email protected]';
        $user->password = bcrypt('user');
        $user->save();
        $user->roles()->attach($userRole);
        $user->permissions()->attach($create_user);
    }
}

DatabaseSeeder\DatabaseSeeder.php

<?php
namespace Database\Seeders;
// use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder
{
    public function run(): void
    {
        $this->call(RoleSeeder::class);
    }
}

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

php artisan db:seed

Шаг 9: Создайте промежуточное программное обеспечение

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

php artisan make:middleware RoleMiddleware

И обновите его следующим образом:App\Http\Middleware\RoleMiddleware.php Теперь зарегистрируйте его внутри kernel.php вот так:

<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
class RoleMiddleware
{
    /**
     * Handle an incoming request.
     *
     * @param  \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response)  $next
     */
    public function handle(
        Request $request,
        Closure $next,
        $role,
        $permission = null
    ): Response {
        if (!$request->user()->hasRole($role)) {
            abort(404);
        }
        if ($permission !== null && !$request->user()->can($permission)) {
            abort(404);
        }
        return $next($request);
    }
}

<?php
namespace App\Http;
use Illuminate\Foundation\Http\Kernel as HttpKernel;
class Kernel extends HttpKernel
{
    /**
     * The application's global HTTP middleware stack.
     *
     * These middleware are run during every request to your application.
     *
     * @var array<int, class-string|string>
     */
    protected $middleware = [
        // \App\Http\Middleware\TrustHosts::class,
        \App\Http\Middleware\TrustProxies::class,
        \Illuminate\Http\Middleware\HandleCors::class,
        \App\Http\Middleware\PreventRequestsDuringMaintenance::class,
        \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
        \App\Http\Middleware\TrimStrings::class,
        \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
    ];
    /**
     * The application's route middleware groups.
     *
     * @var array<string, array<int, class-string|string>>
     */
    protected $middlewareGroups = [
        'web' => [
            \App\Http\Middleware\EncryptCookies::class,
            \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
            \Illuminate\Session\Middleware\StartSession::class,
            \Illuminate\View\Middleware\ShareErrorsFromSession::class,
            \App\Http\Middleware\VerifyCsrfToken::class,
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
        ],
        'api' => [
            // \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
            \Illuminate\Routing\Middleware\ThrottleRequests::class.':api',
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
        ],
    ];
    /**
     * The application's middleware aliases.
     *
     * Aliases may be used instead of class names to conveniently assign middleware to routes and groups.
     *
     * @var array<string, class-string|string>
     */
    protected $middlewareAliases = [
        'auth' => \App\Http\Middleware\Authenticate::class,
        'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
        'auth.session' => \Illuminate\Session\Middleware\AuthenticateSession::class,
        'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
        'can' => \Illuminate\Auth\Middleware\Authorize::class,
        'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
        'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
        'precognitive' => \Illuminate\Foundation\Http\Middleware\HandlePrecognitiveRequests::class,
        'signed' => \App\Http\Middleware\ValidateSignature::class,
        'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
        'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
        'role' => \App\Http\Middleware\RoleMiddleware::class,
    ];
}

Теперь все готово. Мы можем проверить запросы пользователей и роли следующим образом:

resources/views/home.blade.php

@extends('layouts.app')
@section('content')
<div class="container">
    <div class="row justify-content-center">
        <div class="col-md-8">
            <div class="card">
                <div class="card-header">{{ __('Dashboard') }}</div>
                <div class="card-body">
                    @if (session('status'))
                        <div class="alert alert-success" role="alert">
                            {{ session('status') }}
                        </div>
                    @endif
                    @role('admin')
                        {{ __('You are admin') }}
                    @endrole
                    @role('user')
                        {{ __('You are user') }}
                    @endrole
                </div>
            </div>
        </div>
    </div>
</div>
@endsection

Проверьте роли и разрешения пользователей в контроллере:Используйте в своем маршруте следующим образом:

<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class TutorialController extends Controller
{
    public function __invoke()
    {
        if (auth()->user()->can('create-user')) {
            return view('welcome');
        }
    }
}

Использование в групповом маршруте:Читайте также: 

<?php
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\TutorialController;
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider and all of them will
| be assigned to the "web" middleware group. Make something great!
|
*/
Route::get('/', TutorialController::class)->middleware('role:admin');

Route::group(['middleware' => 'role:admin'], function() {
   //
});
Route::group(['middleware' => 'role:user'], function() {
   //
});

Laravel 10 Twilio Отправить SMS Учебное пособие

Заключение

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

Comments

No comments yet
Yurij Finiv

Yurij Finiv

Full stack

Про мене

Professional Fullstack Developer with extensive experience in website and desktop application development. Proficient in a wide range of tools and technologies, including Bootstrap, Tailwind, HTML5, CSS3, PUG, JavaScript, Alpine.js, jQuery, PHP, MODX, and Node.js. Skilled in website development using Symfony, MODX, and Laravel. Experience: Contributed to the development and translation of MODX3 i...

Об авторе CrazyBoy49z
WORK EXPERIENCE
Контакты
Ukraine, Lutsk
+380979856297