كيفية تحديد نوع المستخدم isAdmin في Laravel وحماية صفحات لوحة الإدارة

في معظم تطبيقات Laravel لا يكفي أن نعرف أن المستخدم قام بتسجيل الدخول فقط، بل نحتاج في كثير من الأحيان إلى تحديد ما الذي يُسمح لهذا المستخدم بالوصول إليه بعد تسجيل الدخول.

على سبيل المثال، قد يحتوي التطبيق على نوعين من المستخدمين:

  • User: مستخدم عادي يمكنه الوصول إلى لوحة المستخدم وصفحاته الخاصة.
  • Admin: مدير يمكنه بالإضافة إلى ذلك الوصول إلى لوحة الإدارة وإدارة المستخدمين والمحتوى والإعدادات.

هنا يظهر الفرق بين مفهومين أساسيين في Laravel:

  • Authentication: التحقق من هوية المستخدم ومعرفة هل قام بتسجيل الدخول أم لا.
  • Authorization: تحديد الصلاحيات التي يمتلكها المستخدم بعد تسجيل الدخول.

في هذا الدليل سننشئ نظاماً بسيطاً وعملياً لتحديد المستخدم المدير باستخدام حقل is_admin داخل جدول users، ثم سننشئ Middleware يمنع المستخدمين العاديين من الوصول إلى صفحات الإدارة.

كما سنتعرف على استخدام Blade Directives وGates، ومتى يجب الانتقال من حقل is_admin البسيط إلى نظام Roles & Permissions متكامل.

ما الفرق بين Authentication وAuthorization في Laravel؟

من الأخطاء الشائعة اعتبار تسجيل الدخول والصلاحيات شيئاً واحداً.

عندما يستخدم Laravel Middleware مثل:

auth

فهو يتحقق فقط من أن المستخدم قام بتسجيل الدخول.

لكنه لا يحدد ما إذا كان هذا المستخدم مديراً أو موظفاً أو مستخدماً عادياً.

على سبيل المثال، قد يكون لدينا المستخدمان التاليان:

User Authenticated Admin
Ahmad Yes No
Mohammad Yes Yes

كلا المستخدمين مسجلان للدخول، وبالتالي كلاهما ينجح مع:

middleware('auth')

لكن Mohammad فقط يجب أن يستطيع الدخول إلى:

/admin

وهنا نحتاج إلى Authorization إضافية تحدد من هو Admin.

فكرة نظام is_admin

سنضيف عموداً Boolean إلى جدول users باسم:

is_admin

وستكون القيم:

القيمة نوع المستخدم
0 / false مستخدم عادي
1 / true Admin

بعد ذلك سنقوم بإنشاء Middleware يتحقق من هذا الحقل قبل السماح للطلب بالوصول إلى صفحات الإدارة.

User
 │
 ▼
Login
 │
 ▼
auth Middleware
 │
 ├── Not Authenticated → Login
 │
 ▼
Admin Middleware
 │
 ├── is_admin = false → 403 Forbidden
 │
 ▼
is_admin = true
 │
 ▼
Admin Dashboard

1. تجهيز نظام تسجيل الدخول

يجب أولاً أن يكون لديك نظام Authentication داخل التطبيق.

في إصدارات Laravel القديمة كان من الشائع استخدام Laravel Breeze:

composer require laravel/breeze --dev

php artisan breeze:install

php artisan migrate

npm install

npm run dev

أما إذا كان لديك مشروع قديم يستخدم Breeze بالفعل، فلا يؤثر ذلك على فكرة is_admin التي سنشرحها؛ فالآلية تعتمد على نظام Authentication الأساسي في Laravel وليس على Breeze تحديداً.

2. إضافة حقل is_admin إلى جدول users

لا ينبغي تعديل Migration قديم تم تشغيله على بيئة Production، بل الأفضل إنشاء Migration جديد يضيف الحقل.

نفذ:

php artisan make:migration add_is_admin_to_users_table --table=users

سيتم إنشاء Migration جديد داخل:

database/migrations

قم بتعديله إلى:

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    public function up(): void
    {
        Schema::table('users', function (Blueprint $table) {
            $table->boolean('is_admin')
                ->default(false);
        });
    }

    public function down(): void
    {
        Schema::table('users', function (Blueprint $table) {
            $table->dropColumn('is_admin');
        });
    }
};

لماذا نستخدم default(false)؟

من المهم جداً عدم إنشاء الحقل بهذه الصورة فقط:

$table->boolean('is_admin');

والأفضل:

$table->boolean('is_admin')
    ->default(false);

لأن أي مستخدم جديد يتم تسجيله يجب أن يكون مستخدماً عادياً بشكل افتراضي.

أي أن:

is_admin = false

هي الحالة الافتراضية الآمنة.

ولا يتم منح صلاحية Admin إلا بشكل صريح.

3. تنفيذ Migration

بعد إنشاء Migration نفذ:

php artisan migrate

سيصبح جدول users مثلاً:

id name email password is_admin
1 Ahmad ahmad@example.com ... 0
2 Mohammad mohammad@example.com ... 1

المستخدم رقم 1 مستخدم عادي، بينما المستخدم رقم 2 Admin.

4. إضافة Cast لحقل is_admin داخل User Model

من الأفضل إخبار Eloquent أن حقل is_admin عبارة عن Boolean.

افتح:

app/Models/User.php

ثم أضف Cast للحقل.

في Laravel الحديث يمكن استخدام:

protected function casts(): array
{
    return [
        'email_verified_at' => 'datetime',
        'password' => 'hashed',
        'is_admin' => 'boolean',
    ];
}

وبالتالي عندما نستخدم:

$user->is_admin

سيتعامل Laravel معها كقيمة:

true

أو:

false

بدلاً من الاعتماد على القيمة الرقمية القادمة من قاعدة البيانات.

5. إنشاء Admin Middleware

نقوم الآن بإنشاء Middleware مسؤول عن التحقق من أن المستخدم Admin.

نفذ:

php artisan make:middleware AdminMiddleware

سيقوم Laravel بإنشاء:

app/Http/Middleware/AdminMiddleware.php

6. كتابة AdminMiddleware

افتح الملف وأضف:

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

class AdminMiddleware
{
    public function handle(Request $request, Closure $next): Response
    {
        if (!$request->user() || !$request->user()->is_admin) {
            abort(403, 'Unauthorized action.');
        }

        return $next($request);
    }
}

كيف يعمل AdminMiddleware؟

نستخدم:

$request->user()

للحصول على المستخدم الحالي.

ثم نتحقق من حالتين:

if (!$request->user() || !$request->user()->is_admin)

أي:

  1. هل يوجد مستخدم قام بتسجيل الدخول؟
  2. هل قيمة is_admin لديه تساوي true؟

إذا لم يتحقق أحد الشرطين يتم تنفيذ:

abort(403);

وسيتم إرجاع HTTP Status:

403 Forbidden

أما إذا كان المستخدم Admin فيتم تمرير الطلب:

return $next($request);

لماذا نستخدم $request->user() بدلاً من auth()->user()؟

الطريقتان تعملان في هذا السيناريو:

auth()->user()

و:

$request->user()

لكن استخدام المستخدم المرتبط بالـ Request يجعل Middleware واضحاً ومباشراً، ويجنبنا كذلك محاولة قراءة خاصية is_admin من قيمة null إذا وصل الطلب بدون مستخدم مصادق عليه.

7. تسجيل Middleware في Laravel الحديث

هذه من أهم النقاط التي تختلف بين إصدارات Laravel.

Laravel 11 وما بعده

في البنية الحديثة يتم تسجيل Middleware aliases داخل:

bootstrap/app.php

أولاً قم باستيراد Middleware:

use App\Http\Middleware\AdminMiddleware;
use Illuminate\Foundation\Configuration\Middleware;

ثم:

->withMiddleware(function (Middleware $middleware): void {

    $middleware->alias([
        'admin' => AdminMiddleware::class,
    ]);

})

ويكون جزء من الملف مثلاً:

<?php

use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Exceptions;
use Illuminate\Foundation\Configuration\Middleware;
use App\Http\Middleware\AdminMiddleware;

return Application::configure(
    basePath: dirname(__DIR__)
)
    ->withRouting(
        web: __DIR__.'/../routes/web.php',
        commands: __DIR__.'/../routes/console.php',
        health: '/up',
    )
    ->withMiddleware(function (Middleware $middleware): void {

        $middleware->alias([
            'admin' => AdminMiddleware::class,
        ]);

    })
    ->withExceptions(function (Exceptions $exceptions): void {
        //
    })
    ->create();

أصبح لدينا الآن Middleware alias باسم:

admin

Laravel 10 والإصدارات القديمة

إذا كنت تعمل على Laravel 10 أو إصدار أقدم، ستجد تسجيل Middleware عادة داخل:

app/Http/Kernel.php

مثلاً:

protected $middlewareAliases = [
    'admin' => \App\Http\Middleware\AdminMiddleware::class,
];

8. حماية صفحة Admin

بعد تسجيل Middleware يمكننا استخدامه داخل:

routes/web.php

مثلاً:

use Illuminate\Support\Facades\Route;

Route::get('/admin', function () {

    return view('admin');

})->middleware(['auth', 'admin'])
  ->name('admin');

لاحظ أننا استخدمنا:

['auth', 'admin']

وليس admin فقط.

Middleware الأول:

auth

يتأكد أن المستخدم قام بتسجيل الدخول.

أما:

admin

فيتحقق من صلاحية الإدارة.

9. حماية مجموعة كاملة من Admin Routes

عادة لا تحتوي لوحة الإدارة على Route واحد فقط.

قد يكون لدينا:

/admin
/admin/users
/admin/posts
/admin/settings
/admin/reports

بدلاً من إضافة Middleware لكل Route بشكل منفصل، يمكن استخدام Route Group:

Route::middleware(['auth', 'admin'])
    ->prefix('admin')
    ->name('admin.')
    ->group(function () {

        Route::get('/', function () {
            return view('admin.dashboard');
        })->name('dashboard');

        Route::get('/users', function () {
            return view('admin.users');
        })->name('users');

        Route::get('/settings', function () {
            return view('admin.settings');
        })->name('settings');

    });

ميزة استخدام prefix

عند استخدام:

->prefix('admin')

لا نحتاج إلى كتابة /admin في كل Route.

فمثلاً:

Route::get('/users', ...);

سيصبح عنوانه فعلياً:

/admin/users

ميزة استخدام name prefix

استخدام:

->name('admin.')

يعني أن:

->name('users')

سيصبح:

admin.users

ويمكن استدعاؤه:

route('admin.users')

10. فصل صفحات المستخدم عن صفحات الإدارة

يمكن أن يكون لدينا Dashboard متاحة لجميع المستخدمين المسجلين:

Route::middleware('auth')->group(function () {

    Route::get('/dashboard', function () {

        return view('dashboard');

    })->name('dashboard');

});

ثم Routes إضافية للإدارة:

Route::middleware(['auth', 'admin'])
    ->prefix('admin')
    ->name('admin.')
    ->group(function () {

        Route::get('/', function () {

            return view('admin.dashboard');

        })->name('dashboard');

    });

النتيجة:

Route User Admin
/dashboard
/admin

11. إخفاء روابط Admin من Blade

من الطبيعي ألا نريد إظهار رابط لوحة الإدارة للمستخدم العادي.

داخل Blade يمكن استخدام:

@auth

    @if(auth()->user()->is_admin)

        <a href="{{ route('admin.dashboard') }}">
            Admin Dashboard
        </a>

    @endif

@endauth

أو باستخدام المستخدم المرتبط بالطلب:

@if(auth()->check() && auth()->user()->is_admin)

    <a href="{{ route('admin.dashboard') }}">
        Admin Dashboard
    </a>

@endif

إخفاء الرابط ليس حماية أمنية

هذه نقطة مهمة جداً.

الكود:

@if(auth()->user()->is_admin)

يستخدم فقط لتحديد ما الذي سيظهر في واجهة المستخدم.

لكنه ليس بديلاً عن Middleware.

فحتى لو أخفينا الرابط، يمكن للمستخدم كتابة:

https://example.com/admin

يدوياً في المتصفح.

الحماية الحقيقية يجب أن تكون على السيرفر:

->middleware(['auth', 'admin'])

12. إضافة دالة isAdmin إلى User Model

يمكن جعل الكود أكثر وضوحاً بإضافة Method داخل User Model:

public function isAdmin(): bool
{
    return $this->is_admin;
}

ثم يصبح Middleware:

if (!$request->user() || !$request->user()->isAdmin()) {
    abort(403);
}

وكذلك داخل التطبيق:

if ($user->isAdmin()) {
    // Admin
}

هذا يفصل منطق تحديد الإدارة عن بقية أجزاء التطبيق ويسهل تعديله مستقبلاً.

13. إنشاء أول Admin

يمكن تعديل المستخدم مباشرة باستخدام Laravel Tinker.

شغّل:

php artisan tinker

ثم:

$user = App\Models\User::find(1);

$user->is_admin = true;

$user->save();

أو:

App\Models\User::where('email', 'admin@example.com')
    ->update([
        'is_admin' => true,
    ]);

14. لا تسمح للمستخدم بتحديد is_admin أثناء التسجيل

من الأخطاء الأمنية الخطيرة إضافة:

is_admin

إلى نموذج Registration العام وقراءة قيمته مباشرة من Request.

لا تستخدم مثلاً:

User::create([
    'name' => $request->name,
    'email' => $request->email,
    'password' => Hash::make($request->password),
    'is_admin' => $request->is_admin,
]);

لأن المستخدم يستطيع تعديل HTTP Request يدوياً وإرسال:

is_admin=1

وبذلك قد يمنح نفسه صلاحيات Admin إذا لم توجد طبقات تحقق أخرى.

الأفضل أثناء التسجيل:

User::create([
    'name' => $request->name,
    'email' => $request->email,
    'password' => Hash::make($request->password),
]);

ويترك:

is_admin = false

وفق القيمة الافتراضية في قاعدة البيانات.

15. استخدام Gate بدلاً من Middleware مخصص

Laravel يحتوي على نظام Authorization مدمج يسمى Gates وPolicies.

لحالة بسيطة مثل السماح بالدخول إلى Admin Dashboard يمكن إنشاء Gate.

مثلاً داخل Service Provider:

use App\Models\User;
use Illuminate\Support\Facades\Gate;

public function boot(): void
{
    Gate::define('access-admin', function (User $user) {

        return $user->is_admin;

    });
}

بعد ذلك يمكن حماية Route:

Route::get('/admin', function () {

    return view('admin');

})->middleware(['auth', 'can:access-admin']);

Middleware:

can:access-admin

سيطلب من Laravel التحقق من الـ Gate قبل السماح بالوصول إلى الصفحة.

16. استخدام Gate داخل Blade

ميزة Gates أنها تتكامل مباشرة مع Blade.

يمكن استخدام:

@can('access-admin')

    <a href="{{ route('admin.dashboard') }}">
        Admin Dashboard
    </a>

@endcan

بدلاً من تكرار:

@if(auth()->user()->is_admin)

في أكثر من مكان.

Middleware أم Gate؟

كلا الحلين صحيح، لكن لكل منهما استخدام مناسب.

الحالة الخيار المناسب
منع المستخدم غير الإداري من قسم كامل Middleware
صلاحية عامة مثل Access Admin Gate
صلاحيات مرتبطة بـ Model مثل تعديل Post Policy
نظام Roles وصلاحيات معقد Roles & Permissions

17. استخدام Policies للصلاحيات المرتبطة بالبيانات

لنفرض أن المستخدم يستطيع الدخول إلى لوحة الإدارة، لكن ليس كل Admin يجب أن يكون قادراً على حذف Posts.

هنا يصبح الحقل:

is_admin

غير كافٍ للتعبير عن جميع الصلاحيات.

يمكن استخدام Laravel Policies لتنظيم صلاحيات مثل:

view
create
update
delete
restore
forceDelete

على Models معينة.

مثلاً:

php artisan make:policy PostPolicy --model=Post

ثم داخل Policy يمكن تحديد من يستطيع حذف Post:

public function delete(User $user, Post $post): bool
{
    return $user->is_admin;
}

18. متى لا يكون is_admin كافياً؟

حقل Boolean مناسب عندما يكون النظام بسيطاً جداً:

User
Admin

لكن تخيل تطبيقاً يحتوي على:

Super Admin
Admin
Manager
Editor
Support
Accountant
User

وصلاحيات مثل:

view users
create users
edit users
delete users

view reports
export reports

edit settings

view invoices
create invoices
refund invoices

في هذه الحالة إنشاء حقول:

is_admin
is_manager
is_editor
is_support
is_accountant

ليس تصميماً جيداً وقابلاً للتوسع.

الأفضل بناء نظام:

Users
  │
  ▼
Roles
  │
  ▼
Permissions

بحيث يمكن إعطاء المستخدم Role واحداً أو أكثر وكل Role يحتوي مجموعة Permissions.

19. is_admin أم role؟

هناك طريقة أخرى بسيطة وهي استخدام حقل:

role

مثلاً:

user
admin
manager

بدلاً من:

is_admin

حقل is_admin ممتاز عندما لا يوجد إلا حالتان:

Admin
Not Admin

أما إذا كان التطبيق يحتوي عدة أنواع من المستخدمين، فإن Role أو نظام Roles & Permissions سيكون أكثر مرونة.

20. إرجاع 403 أم إعادة التوجيه؟

في Middleware استخدمنا:

abort(403);

وهذا هو السلوك الصحيح أمنياً عندما يكون المستخدم Authenticated لكنه لا يملك الصلاحية.

الفرق:

Status المعنى
401 Unauthorized لم تتم المصادقة على المستخدم
403 Forbidden المستخدم معروف لكنه لا يملك الصلاحية المطلوبة

لذلك المستخدم الذي قام بتسجيل الدخول ولكنه ليس Admin يناسبه:

403 Forbidden

21. تخصيص صفحة خطأ 403

بدلاً من عرض صفحة Laravel الافتراضية يمكن إنشاء:

resources/views/errors/403.blade.php

مثلاً:

<!DOCTYPE html>
<html lang="ar" dir="rtl">

<head>

    <meta charset="UTF-8">

    <meta name="viewport"
          content="width=device-width, initial-scale=1.0">

    <title>غير مصرح لك بالدخول</title>

</head>

<body>

    <main>

        <h1>403</h1>

        <h2>غير مصرح لك بالدخول إلى هذه الصفحة</h2>

        <p>
            لا يمتلك حسابك الصلاحيات المطلوبة للوصول إلى هذا القسم.
        </p>

        <a href="{{ route('dashboard') }}">
            العودة إلى لوحة التحكم
        </a>

    </main>

</body>

</html>

22. Middleware الكامل

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

class AdminMiddleware
{
    public function handle(
        Request $request,
        Closure $next
    ): Response {

        if (
            !$request->user() ||
            !$request->user()->is_admin
        ) {

            abort(403);

        }

        return $next($request);
    }
}

23. User Model

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;

class User extends Authenticatable
{
    use HasFactory, Notifiable;

    protected $fillable = [
        'name',
        'email',
        'password',
    ];

    protected $hidden = [
        'password',
        'remember_token',
    ];

    protected function casts(): array
    {
        return [
            'email_verified_at' => 'datetime',
            'password' => 'hashed',
            'is_admin' => 'boolean',
        ];
    }

    public function isAdmin(): bool
    {
        return $this->is_admin;
    }
}

24. نقطة أمنية مهمة حول $fillable

لاحظ أننا لم نضع:

is_admin

ضمن:

$fillable

في هذا المثال.

السبب أن جعل الحقل Mass Assignable دون الحاجة إليه قد يزيد خطر تعيينه عن طريق الخطأ في عمليات مثل:

User::create($request->all());

أو:

$user->update($request->all());

يفضل دائماً تحديد الحقول المسموح للمستخدم بتعديلها بشكل صريح وعدم تمرير كل محتويات Request مباشرة إلى Model.

25. Routes كاملة

<?php

use Illuminate\Support\Facades\Route;

Route::middleware('auth')->group(function () {

    Route::get('/dashboard', function () {

        return view('dashboard');

    })->name('dashboard');

});


Route::middleware(['auth', 'admin'])
    ->prefix('admin')
    ->name('admin.')
    ->group(function () {

        Route::get('/', function () {

            return view('admin.dashboard');

        })->name('dashboard');


        Route::get('/users', function () {

            return view('admin.users');

        })->name('users');


        Route::get('/settings', function () {

            return view('admin.settings');

        })->name('settings');

    });

26. التسلسل الكامل لطلب Admin

عندما يزور المستخدم:

/admin

يمر الطلب بالتسلسل التالي:

Browser
   │
   ▼
GET /admin
   │
   ▼
auth Middleware
   │
   ├── Guest
   │     └── Redirect to Login
   │
   ▼
Authenticated User
   │
   ▼
AdminMiddleware
   │
   ├── is_admin = false
   │     └── 403 Forbidden
   │
   ▼
is_admin = true
   │
   ▼
Route / Controller
   │
   ▼
Admin View

وبذلك لدينا طبقتان منفصلتان:

Authentication
+
Authorization

27. أخطاء شائعة في نظام is_admin

حماية الرابط في Blade فقط

إخفاء رابط Admin ليس حماية. يجب حماية Route على السيرفر.

عدم استخدام auth Middleware

إذا افترض Middleware دائماً وجود مستخدم ثم استخدمت:

auth()->user()->is_admin

فقد تواجه خطأ إذا كان المستخدم Guest.

السماح بتعديل is_admin من Profile

لا تسمح للمستخدم بإرسال is_admin ضمن بيانات تحديث حسابه.

جعل المستخدم Admin أثناء التسجيل بناء على Request

هذه ثغرة صلاحيات خطيرة ويجب تجنبها.

استخدام is_admin لنظام صلاحيات ضخم

عندما تتعدد أنواع المستخدمين والصلاحيات، انتقل إلى Roles وPermissions أو Policies.

استخدام Kernel.php في مشروع Laravel حديث

الشروحات القديمة تسجل Middleware aliases داخل app/Http/Kernel.php، بينما تستخدم بنية Laravel الحديثة bootstrap/app.php.

28. تحسين إضافي: إضافة verified

إذا كنت تريد السماح للإدارة فقط للمستخدمين الذين أكدوا بريدهم الإلكتروني، يمكن إضافة:

verified

فتصبح المجموعة:

Route::middleware([
    'auth',
    'verified',
    'admin'
])->group(function () {

    // Admin routes

});

وبذلك يجب أن يكون المستخدم:

  1. مسجل الدخول.
  2. أكد البريد الإلكتروني.
  3. يمتلك صلاحية Admin.

29. هل is_admin نظام آمن؟

نعم، استخدام Boolean مثل is_admin يمكن أن يكون حلاً آمناً ومناسباً إذا كان التطبيق يحتاج فقط إلى التمييز بين:

User
Admin

الأمان لا يعتمد على اسم الحقل، بل على طريقة تطبيق Authorization.

يجب أن يكون التحقق من الصلاحية على السيرفر، وألا يستطيع المستخدم تعديل قيمة is_admin بنفسه، وأن تتم حماية جميع Admin Routes باستخدام Middleware أو Gate أو Policy مناسب.

30. ما التصميم الذي يجب استخدامه؟

يمكن تلخيص الاختيار بالشكل التالي:

حجم النظام التصميم المناسب
User / Admin فقط is_admin Boolean
عدة أنواع مستخدمين بسيطة role
صلاحيات على Models Laravel Policies
صلاحيات عامة Laravel Gates
نظام إداري كبير Roles & Permissions

الخلاصة

تسجيل الدخول في Laravel لا يعني أن المستخدم يمتلك حق الوصول إلى جميع أجزاء التطبيق. يقوم Authentication بإثبات هوية المستخدم، بينما تقوم Authorization بتحديد ما يستطيع هذا المستخدم القيام به.

عندما يكون التطبيق بسيطاً ويحتوي على مستخدم عادي ومدير فقط، فإن إضافة حقل Boolean باسم:

is_admin

إلى جدول users تعتبر طريقة بسيطة وفعالة.

البنية الكاملة تصبح:

users.is_admin
       │
       ▼
User Model Cast
       │
       ▼
Authentication
       │
       ▼
Admin Middleware
       │
       ▼
Protected Admin Routes
       │
       ▼
Admin Dashboard

أما إذا تطور التطبيق وأصبح يحتوي على أنواع متعددة من المستخدمين وصلاحيات مختلفة، فمن الأفضل عدم إضافة المزيد من حقول Boolean، بل الانتقال إلى Laravel Gates وPolicies أو بناء نظام Roles & Permissions متكامل.

وأياً كان التصميم المستخدم، يجب تطبيق قاعدة أساسية: لا تعتمد على إخفاء الأزرار أو الروابط في الواجهة كوسيلة للحماية، بل يجب تنفيذ التحقق من الصلاحيات دائماً على السيرفر قبل تنفيذ العملية أو عرض المورد المحمي.