• Czas czytania ~8 min
  • 10.09.2023

Istnieje kilka pakietów dla Laravel do zarządzania rolami użytkowników i uprawnieniami. Role i uprawnienia Spaties oraz role i uprawnienia Laratrust są najpopularniejszymi z nich. Możemy łatwo zarządzać rolami i uprawnieniami w Laravel za pomocą tych pakietów. Ale w tym samouczku naszym celem jest utworzenie systemu ról i uprawnień bez żadnych pakietów. Więc nie będziemy używać żadnego rodzaju pakietu do tworzenia tego systemu ról i uprawnień Laravel 10.

W tym samouczku stworzę kompletny Laravel 10 ról i uprawnień bez pakietu. Aby utworzyć te role Laravel i systemy uprawnień, musimy najpierw zrozumieć scenariusz ról i uprawnień dla użytkownika. Więc co zrobimy w tym samouczku, zobaczmy scenariusz:

  • Użytkownik może mieć rolę
  • Rola może mieć wiele uprawnień
  • Użytkownicy mogą mieć wiele ról

To jest wymóg, który zamierzamy wdrożyć. Implementujemy również dyrektywę oprogramowania pośredniczącego i niestandardową dyrektywę kasetową do obsługi zalogowanych użytkowników zgodnie z ich rolami i uprawnieniami.

laravel-custom-role-and-permission-inplementation

Zobaczmy obraz podglądu pulpitu nawigacyjnego tej roli i uprawnień Laravel 10 samouczek:Zalogowany jako rola użytkownika:Krok 1: Pobierz świeży Laravel W pierwszym kroku ról i uprawnień Laravel

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

10 bez pakietu, pobierz nową aplikację Laravel, wykonując następujące polecenie:Krok 2: 

laravel-10-roles-and-permissions-tutorial

composer create-project laravel/laravel example-app

Utwórz uwierzytelnianie

Potrzebujemy uwierzytelniania. Aby utworzyć proste uwierzytelnianie bootstrap za pomocą następującego polecenia:Krok 3: Połącz bazę danych Teraz podłącz bazę danych

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

, ponieważ potrzebujemy migracji dla tego Laravel role i uprawnienia przykład:.env

Krok 4:

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

Utwórz model

Potrzebujemy modelu, aby nadać użytkownikom role i uprawnienia. Stwórzmy więc nasz model za pomocą poniższego polecenia, aby ukończyć Laravel 10 ról i uprawnień bez pakietu.

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

Teraz zaktualizuj plik migracji, taki jak: Migracje dla tabeli uprawnień:

<?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');
    }
};

Teraz czas utworzyć wiele tabel przestawnych, utworzymy nowy plik migracji dla tabeli users_permissions. Uruchom poniższe polecenie,

<?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');
    }
};

aby utworzyć

<?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');
    }
};

Teraz utwórzmy tabelę przestawną dla 

<?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_rolesW ramach określonej roli użytkownik może mieć określone uprawnienia. Na przykład użytkownik może mieć uprawnienia do publikowania tematu, a administrator może mieć uprawnienia do edytowania lub usuwania tematu. W takim przypadku skonfigurujmy nową tabelę dla roles_permissions, aby poradzić sobie z tą złożonością.

php artisan make:migration create_roles_permissions_table --create=roles_permissions

Teraz zaktualizuj podobne:Teraz uruchom następujące polecenie, aby utworzyć migrację

<?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');
    }
};

Krok5: Aktualizuj model z relacją

php artisan migrate

Teraz zaktualizuj model roli za pomocą relacji takiej jak ta: app\Models\Role.php Teraz zaktualizuj roles_permissions model uprawnień za pomocą relacji takiej jak ta:

Krok 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');
    }
}

Utwórz cechę usługi

Teraz w tym kroku utworzymy usługę lub cechę pomocniczą, aby łatwo obsługiwać role i uprawnienia w aplikacji 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();
    }
}

Teraz zaktualizuj model użytkownika przy użyciu tej cechy.

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',
    ];
}

Krok 7: Utwórz dyrektywę

Role BladeTym razem stworzymy dyrektywę ostrzową@role(). Zaktualizuj dostawcę usług aplikacji w następujący sposób: Krok 8:

Krok 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; ?>";
        });
    }
}

Utwórz siewcę

Teraz w tym kroku utworzymy pewne dane pozorne, aby utworzyć role i uprawnienia z użytkownikami. Uruchom więc poniższe polecenie:Teraz zaktualizuj go w następujący sposób: Baza danych \ Seeders \ RoleSeeder.php Teraz zaktualizuj seeder bazy danych w następujący sposób:

php artisan make:seeder RoleSeeder

DatabaseSeeder \ DatabaseSeeder.php

<?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);
    }
}

Teraz uruchom poniższe polecenie,

<?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);
    }
}

aby wygenerować fałszywe dane, aby przetestować nasze role i uprawnienia laravel 10 bez aplikacji pakietu.

php artisan db:seed

Krok 9: Utwórz oprogramowanie

pośrednicząceW tym kroku utworzymy oprogramowanie pośredniczące roli, abyśmy mogli obsługiwać żądania użytkowników przy użyciu oprogramowania pośredniczącego.

php artisan make:middleware RoleMiddleware

I zaktualizuj go w następujący sposób: App \ HTTP \ Middleware \ RoleMiddleware.php Teraz zarejestruj go w kernel.php następujący sposób:

<?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);
    }
}

App \ HTTP \ Kernel.php

<?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,
    ];
}

Teraz wszystko jest gotowe. Możemy sprawdzić żądania użytkowników i role w następujący sposób:

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

Sprawdź role i uprawnienia użytkowników w kontrolerze:Użyj na trasie w następujący sposób:trasy/sieć Web.php

<?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');
        }
    }
}

Użyj w trasie grupowej:Czytaj także: 

<?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 Wyślij SMS Samouczek

Wniosek

Spójrz na to, wdrożyliśmy wszystkie wymagania związane z rolami i uprawnieniami. Mam nadzieję, że teraz w każdej aplikacji Laravel, jesteśmy w stanie wdrożyć te role i uprawnienia laravel 10 bez pakietu. Mam nadzieję, że ten samouczek ról i uprawnień laravel ci pomoże.

Comments

No comments yet
Yurij Finiv

Yurij Finiv

Full stack

O

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...

O autorze CrazyBoy49z
WORK EXPERIENCE
Kontakt
Ukraine, Lutsk
+380979856297