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

ويتمثل النظام في ثلاث محاور أساسية المُستخدم و الدور و الصلاحية:

  • المُستخدم يُمكن أن يكون له أكثر من دور.

  • الدور يُمكن اسناده لأكثر من مُستخدم.

  • الدور يكون له أكثر من صلاحية.

  • الصلاحية يُمكن اسنادها لأكثر من دور.

هذه هي القواعد الأساسية لهذا النظام

ملاحظة: النظام يكون فعال بشكل أكبر في حال كثرة عدد المُستخدمين المراد إعطائهم صلاحيات.

إن كانت الصلاحيات كثيرة ومتشعبة وتندرج تحت أكثر من قسم يُمكن إنشاء تصنيفات لتجميع الصلاحيات التي تندرج تحت تصنيف مُعين للتنظيم وسهولة التعامل معها.

سنأخذ مثال عملي كتطبيق على هذا:

  • لدينا موقع يحتوي على واجهة الموقع ومدونة ولوحة تحكم لكل قسم منهم صلاحياته ولدينا مُستخدمين للنظام وأدوار ستوزع عليها الصلاحيات

سكيون لدينا الأدوار panelUser, panelEditor, panelAdmin خاصة بلوحة تحكم الموقع

والأدوار siteUser, siteEditor, siteAdmin خاصة بواجهة الموقع

والأدوار blogUser, blogEditor, blogAdmin خاصة بمدونة الموقع

للتنظيم سنقسم الصلاحيات تحت عدة ثلاث تصانيف وهي panel و site و blog

الصلاحيات الخاصة بلوحة التحكم "panel" هي

 panel.user.add
 panel.user.edit
 panel.user.delete
 panel.theme.add
 panel.theme.edit
 panel.theme.delete
 panel.theme.change

... وهكذا لأي عدد من الصلاحيات التي تريدها للوحة التحكم

الصلاحيات الخاصة بالموقع "site" هي

site.category.add
site.category.edit
site.category.delete
site.subcategory.add
site.subcategory.edit
site.subcategory.delete
site.subcategory.add
site.product.add
site.product.edit
site.product.delete
site.product.changePrice
site.product.changeImage
site.product.changeStatus

... وهكذا لأي عدد من الصلاحيات التي تريدها للموقع

الصلاحيات الخاصة بالمدونة "blog" هي

blog.post.add
blog.post.edit
blog.post.delete
blog.comment.add
blog.comment.edit
blog.comment.delete

... وهكذا لأي عدد من الصلاحيات التي تريدها للمدونة

الآن يُمكن اسناد أي من الصلاحيات لأي قسم من الأقسام الثلاثة سواء المدونة والموقع ولوحة التحكم للدور الذي تريده، وتستطيع تطبيق النقاط الأربعة السالفة ذكرها لنظام الصلاحيات في الأعلى.

سنأخذ مثال: الدور panelAdmin سيُعطي جميع الصلاحيات الخاصة بلوحة التحكم الدور panelUser سيُعطى صلاحيات الإضافة فقط الخاصة بلوحة التحكم ... وهكذا بحيث تستطيع تغيير الصلاحيات المُسندة للأدواء كيفما تشاء أو إنشاء أدوار جديدة وإسنداد صلاحيات مُعينة لها.

الآن لدينا مُستخدمين ahmed و mohamed و motafa يُمكن أن يتم اسناد دور أو عدة أدوار لأي من المستخدمين كمثال أحمد تم إسناد الدور panelEditor للوحة التحكم و siteAdmin في الموقع الآن أحمد يستطيع تنفيذ جميع الصلاحيات التي تندرج تحت كلا الدورين panelEditor و siteAdmin وهكذا يُمكن إعطاء الصلاحيات للمُستخدمين عبر نظام الأدوار.

هذا بالنسبة للجذء النظري الذي يشرح كيف تسير الأمور في نظام صلاحيات الأدوار سنطبق هذا النظام بشكل عملي باستخدام قواعد البيانات MySQL ولغة البرمجة PHP عبر استخدام إطار العمل 5.3 Laravel فلنبدأ.

أولاً: سيكون لدينا عدة جداول:

  • جدول المستخدمين users
  • جدول الأدوار roles
  • جدول أقسام الصلاحيات sections (جدول لتظيم عرض الصلاحيات)
  • جدول الصلاحيات pemissions
  • جدول لربط الصلاحيات بالأدوار role_pemissions
  • جدول لربط الأدوار بالمستخدمين user_roles

إنشاء الجداول عبر Laravel

Schema::create('roles', function ($table) {
    $table->increments('id');
    $table->string('name');
    $table->string('desc')->nullable();
});
Schema::create('sections', function ($table) {
    $table->increments('id');
    $table->string('name');
    $table->string('desc')->nullable();
});
Schema::create('permissions', function ($table) {
    $table->increments('id');
    $table->string('name');
    $table->string('desc')->nullable();
    $table->integer('section_id');
    $table->foreign('section_id')->references('id')->on('sections');
});
Schema::create('role_permissions', function ($table) {
    $table->increments('id');
    $table->integer('role_id');
    $table->integer('permission_id');
    $table->foreign('role_id')->references('id')->on('roles');
    $table->foreign('permission_id')->references('id')->on('permissions');
});
Schema::create('user_roles', function ($table) {
    $table->increments('id');
    $table->integer('user_id');
    $table->integer('role_id');
    $table->foreign('user_id')->references('id')->on('users');
    $table->foreign('role_id')->references('id')->on('roles');
});

سنستخدم الـ Laravel eloquent في عمل العلاقات بين الجداول سنضع الفئات الخاصة بالجداول في مجلد باسم Tables داخل المجلد App وتكون العلاقات كالتالي:

  • جدول المستخدمين users:

    <?php
    
    namespace App;
    
    use Illuminate\Notifications\Notifiable;
    use Illuminate\Foundation\Auth\User as Authenticatable;
    
    class User extends Authenticatable
    {
        use Notifiable;
    
        protected $fillable = [
            'name', 'email', 'password'
        ];
    
        protected $hidden = [
            'password', 'remember_token',
        ];
    
        public function roles()
        {
            return $this->hasMany('App\Tables\UserRole');
        }
    
        public function hasRole($role)
        {
            foreach($this->roles as $row){
                if($row->role->name == $role) return true;
            }
            return false;
        }
    
        public function hasPermission($permission)
        {
            foreach($this->roles as $row){
                foreach($row->role->permissions as $row2){
                    if($row2->permission->name == $permission) return true;
                }
            }
            return false;
        }
    }
    
  • جدول الأدوار roles:

    <?php
    
    namespace App\Tables;
    
    use Illuminate\Database\Eloquent\Model;
    
    class Role extends Model
    {
        protected $table = 'roles';
        public $timestamps = false;
    
        public function permissions()
        {
            return $this->hasMany('App\Tables\RolePermission');
        }
    }
    
  • جدول استرشادي لأقسام الصلاحيات sections:

    <?php
    
    namespace App\Tables;
    
    use Illuminate\Database\Eloquent\Model;
    
    class Section extends Model
    {
        protected $table = 'sections';
        public $timestamps = false;
    
        public function permissions()
        {
            return $this->hasMany('App\Tables\RolePermission');
        }
    }
    
  • جدول الصلاحيات permissions:

    <?php
    
    namespace App\Tables;
    
    use Illuminate\Database\Eloquent\Model;
    
    class Permission extends Model
    {
        protected $table = 'permission';
        public $timestamps = false;
    
        public function permissions()
        {
            return $this->hasMany('App\Tables\RolePermission');
        }
    
        public function section()
        {
            return $this->belongsTo('App\Tables\Section');
        }
    
        public function assignTo($role_id)
        {
            return ($this->permissions->where('role_id', $role_id)->count() > 0)?true:false;
        }
    }
    
  • جدول صلاحيات الأدوار role_pemissions:

    <?php
    
    namespace App\Tables;
    
    use Illuminate\Database\Eloquent\Model;
    
    class RolePermission extends Model
    {
        protected $table = 'role_permissions';
        public $timestamps = false;
    
        public function role()
        {
            return $this->belongsTo('App\Tables\Role');
        }
    
        public function permission()
        {
            return $this->belongsTo('App\Tables\Permission');
        }
    }
    
  • جدول أدوار المستخدمين user_roles:

    <?php
    
    namespace App\Tables;
    
    use Illuminate\Database\Eloquent\Model;
    
    class UserRole extends Model
    {
        protected $table = 'user_roles';
        public $timestamps = false;
    
        public function role()
        {
            return $this->belongsTo('App\Tables\Role');
        }
    
        public function user()
        {
            return $this->belongsTo('App\User');
        }
    }
    

والآن بعد تهيئة نظام الصلاحيات نستطيع إنشاء الأدوار والصلاحيات وإسناد الصلاحيات للأدوار والأدوار للمستخدمين:

  • لإنشاء دور جديد:

    App\Tables\Role::firstOrCreate(['name' => 'panelAdmin']);
    
  • لإنشاء قسم خاصة لتصنيف الصلاحيات من خلالها:

    App\Tables\Section::firstOrCreate(['name' => 'panel']);
    
  • لإنشاء صلاحية جديدة:

    App\Tables\Permission::firstOrCreate(['name' => 'panel.user.add', 'section_id'=>1 /* panel section id = 1 */ ]);
    
  • لإسناد صلاحية لدور ما:

    App\Tables\RolePermission::firstOrCreate(['permission_id' => 1 /* panel.user.add permission id = 1 */, 'role_id'=>1 /* panelAdmin role id = 1 */ ]);
    
  • لإسناد دور لمستخدم ما:

    App\Tables\UserRole::firstOrCreate(['user_id' => 1 /* ahmed user id = 1 */, 'role_id'=>1 /* panelAdmin role id = 1 */ ]);
    

يُمكن إجراء عمليات الإنشاء والتعديل والحذف الإسناد من خلال واجهة رسومية عبر لوحة التحكم لسهولة إنشاء الصلاحيات والأدوار وأسناد الصلاحيات للأدوار أو الأدوار للمستخدمين أو تعديلها وقتما تشاء.

الآن داخل البرمجة سنستخدم الدالة hasRole من خلال الكائن المنشأ من المُستخدم عبر الـ eloquent للتحقق من أن هذا الدور المُمرر للدالة مُسند لهذا المُستخدم أم لا كالتالي:

    $user = User::where('id', 1)->first();

    if($user->hasRole('panelAdmin')){
        echo 'Yes';
    }else{
        echo 'No';
    }
  • والدالة hasPermission للتحقق من أن المُستخدم يملك تلك الصلاحية أم لا كالتالي:

    $user = User::where('id', 1)->first();
    
    if($user->hasPermission('panel.user.add')){
        echo 'Yes';
    }else{
        echo 'No';
    }