Mahmoud Alrashidi نشر 15 فبراير 2021 أرسل تقرير نشر 15 فبراير 2021 كيف يُمكن إنشاء مُستخدمين و تقسيمهم حسب صلاحيات مُحددة، مثلاً إنشاء مُستخدمين لهم دور مدير و مستخدمين لهم دور مٌحاسب في النظام مع تحديد صلاحيات المُحاسب و مُستخدمين عاديين ... الخ 1 اقتباس
0 عبد الله محمد5 نشر 15 فبراير 2021 أرسل تقرير نشر 15 فبراير 2021 اللارافيل تسهل القيام بذلك من خلال امرين: البوابات او الgates : وهي عبارة عن بوابة تعطي المرور للمستخدمين المصرح لهم القيام بالواجبات المعينة. ويتم تعريف البوابات بداخل الدالة boot use App\Models\Post; use App\Models\User; use Illuminate\Support\Facades\Gate; /** * Register any authentication / authorization services. * * @return void */ public function boot() { $this->registerPolicies(); Gate::define('update-post', function (User $user, Post $post) { return $user->id === $post->user_id; }); } في الكود الموجود بالأعلى يتم إنشاء بوابة تقوم بتحديد عملية تحديث الpost للشخص الذي قام بانشائه فقط وذلك من خلال مقارنة الid الخاص بالمستخدم الحالي مع الid الخاص بالمستخدم الذي قام بإنشاء الpost. <?php namespace App\Http\Controllers; use App\Http\Controllers\Controller; use App\Models\Post; use Illuminate\Http\Request; use Illuminate\Support\Facades\Gate; class PostController extends Controller { /** * Update the given post. * * @param \Illuminate\Http\Request $request * @param \App\Models\Post $post * @return \Illuminate\Http\Response */ public function update(Request $request, Post $post) { if (! Gate::allows('update-post', $post)) {//هنا يتم التأكد باستخدام البوابة update-post من أن المستخدم مصرح له تحديث ال post abort(403);//يتم اجهاض العملية مع الخطأ 403 اي أن المستخدم غير مصرح للقيام بالعملية } // متابعة الكود وتحديث المنشور } } بعد عملية إنشاء الgate يأتي الدور على ربط البوابة مع الcontroller حيث تم وضع شرط لمواصلة تنفيذ التحديث على البوست وهو ان تكون قيمة البوابة قيمة ايجابية اي ان المستخدم مصرح له القيام بالامر. : او السياسات policies من خلال ال php artisan make:policy PostPolicy --model=Post خاصة بالموديل بوست حتكون موجودة في المسار policy الامر ده من خلاله سيتم إنشاء app/Policies بعدها ستقوم بتسجيل السياسة التي قمت بعملها في المسار App\Providers\AuthServiceProvider والتسجيل بمثابة اخبار للارافيل بالسياسات التي ستستخدمها في البرنامج. <?php namespace App\Policies; use App\Models\Post; use App\Models\User; class PostPolicy { /** * Determine if the given post can be updated by the user. * * @param \App\Models\User $user * @param \App\Models\Post $post * @return bool */ public function update(User $user, Post $post) { return $user->id === $post->user_id; } } في الكود السابق يتم التحقق من أن المستخدم مصرح له أن يقوم بعملية التحديث. وتقدر تستخدم الpolicy بواحدة من طريقتين: اما عن طريق الblade : @can('update', $post) <!-- ...بتقوم بعرض جزئيات من التصميم للمستخدم في حال انه كان يمكنه عمل تحديث للبوست --> @elsecan('create', App\Models\Post::class) <!-- ...بتقوم بعرض جزئيات من التصميم للمستخدم في حال انه كان يمكنه عمل انشاء لبوست جديد--> @endcan @cannot('update', $post) <!-- ...تقوم بعرض جزئيات من التصميم للمستخدم في حال انه كان لا يمكنه عمل تحديث للبوست --> @elsecannot('create', App\Models\Post::class) <!-- ...بتقوم بعرض جزئيات من التصميم للمستخدم في حال انه كان لا يمكنه عمل انشاء لبوست جديد--> @endcannot عن طريق الربط مع الcontroller: <?php namespace App\Http\Controllers; use App\Http\Controllers\Controller; use App\Models\Post; use Illuminate\Http\Request; class PostController extends Controller { /** * Update the given post. * * @param \Illuminate\Http\Request $request * @param \App\Models\Post $post * @return \Illuminate\Http\Response */ public function update(Request $request, Post $post) { if ($request->user()->cannot('update', $post)) { abort(403); } // Update the post... } } 1 اقتباس
0 أسامة كمال النبريص نشر 15 فبراير 2021 أرسل تقرير نشر 15 فبراير 2021 في البداية يجب عليك تجهيز بعض الجداول للقيام بذلك, فستحتاج على الأقل إلى جدول للأدوار وجدول للصلاحيات وجدول صلاحيات الدور. كل واحد منها يحمل الاسم الذي سيتعامل معه النظام, كالتالي: Schema::create('permissions', function (Blueprint $table) { $table->bigIncrements('id'); $table->string('name'); $table->timestamps(); }); هذا للصلاحيات وكذلك للأدوار كالتالي: Schema::create('roles', function (Blueprint $table) { $table->bigIncrements('id'); $table->string('name'); $table->timestamps(); }); أما لجدول صلاحيات الدور فسيحتوي على id لكل دور يقابله الصلاحيات المعطاه له كالتالي: Schema::create('role-permissions', function (Blueprint $table) { $table->bigIncrements('id'); $table->unsignedBigInteger('role_id'); $table->unsignedBigInteger('permission_id'); $table->timestamps(); $table->foreign('role_id')->references('id')->on('roles'); $table->foreign('permission_id')->references('id')->on('permissions'); }); حيث أن هذا الجدول مخصص للعلاقة وربط بين الجدولين. بالطبع سنحتاج إلى Models لل Role و Permission حتى نستطيع التعامل مع الجداول سأفترض معرفتك بهذا الأمر ولكن سأوضح العلاقة الموجودة والتي هي واحد لمجموعة 1:m وممثلة كالتالي في Permission model: public function role(): { return $this->belongsTo(Role::class); } وفي Role model: public function permission(): { return $this->hasMany(Permission::class); } هكذا تكونت العلاقات لدينا, الأن نريد أن نضيف عمود جديد في جدول users باسم role حتى نستطيع إعطاءه الدور الخاص به. وهذا يعني أننا نريد أن ننشئ الصلاحيات ومن ثم تحديد هذه الصلاحيات حسب دور محدد ومن ثم نعطي هذا الدور للمستخدم وبهذا الشكل سيمتلك المستخدم الصلاحيات. ولكن نريد تطبيق ذلك في المشروع لدينا وهذا يتم عبر ال Middlewate غالباً لكن يمكن فحصه في controller بداخل ال constructor الخاص بهذا ال controller ولكن دعنا نقول أننا نريد التعامل باستخدام Middleware فما علينا فعله هو أن نتأكد بداخله إن كان هذا المستخدم لديه الصلاحيات لدخول إلى صفحة معينة أو القيام بأمر معين. وعلى المستوي الشخصي أستخدم مكتبة جاهزة توفر الوقت علي بهذا الأمر وتقوم به بطريقة ممتازة واسم هذه المكتبة Laravel-permission فكل ما عليك فعله هو تتبع خطوات التنزيل الموضحة ومن ثم تعلم استخدام المكتبة. 1 اقتباس
0 سمير عبود نشر 16 فبراير 2021 أرسل تقرير نشر 16 فبراير 2021 هناك عدة حزم مُعظم المُطورون يستخدمون إحداها لعمل هذه الجزئية في مشروعهم و من هذه الحزم أذكر: Laravel-permission التي تم تطويرها من طرف spatie و هم معروفين بتطوير عدة حزم مشهورة و مُستخدمة و يُطورون عليها بإستمرار. bouncer من تطوير Joseph Silber Laratrust هذه الحزم أكثر إستخداماً في هذا الموضوع و هي تُحدث بإستمرار حتى تدعم الإصدارات الجديدة من إطار laravel. إن كنت تريد إنجاز هذا الأمر فستتعب قليلاً و هذه الخطوات يُمكنك تطبيقها للوصول إلى ما تريد: إنشاء مودل لكل من Role و Permission و ملف تهجير لكل منهما: php artisan make:model Permission -m php artisan make:model Role -m كما تعلم فتمرير -m يعني أننا نريد إنشاء ملف تهجير أيضاً. تعديل ملفات التهجير: ملف تهجير الصلاحيات: <?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; class CreatePermissionsTable extends Migration { public function up() { Schema::create('permissions', function (Blueprint $table) { $table->id(); $table->string('name'); // edit posts $table->string('slug'); //edit-posts $table->timestamps(); }); } public function down() { Schema::dropIfExists('permissions'); } } ملف تهجير الأدوار: <?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; class CreateRolesTable extends Migration { public function up() { Schema::create('roles', function (Blueprint $table) { $table->id(); $table->string('name'); $table->string('slug'); $table->timestamps(); }); } public function down() { Schema::dropIfExists('roles'); } } إنشاء ملفات تهجير الجداول الإضافية لربط الصلاحيات بالمستخدمين و ربط الصلاحيات بالأدوار و ربط الأدوار بالمُستخدمين: php artisan make:migration create_users_permissions_table --create=users_permissions php artisan make:migration create_users_roles_table --create=users_roles php artisan make:migration create_roles_permissions_table --create=roles_permissions و في ما يلي مُحتوى ملفات التهجير التي أنشأناها: جدول users_permissions: <?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; class CreateUsersPermissionsTable extends Migration { public function up() { Schema::create('users_permissions', function (Blueprint $table) { $table->unsignedBigInteger('user_id'); $table->unsignedBigInteger('permission_id'); //FOREIGN KEY CONSTRAINTS $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); $table->foreign('permission_id')->references('id')->on('permissions')->onDelete('cascade'); //SETTING THE PRIMARY KEYS $table->primary(['user_id','permission_id']); }); } public function down() { Schema::dropIfExists('users_permissions'); } } جدول users_roles: <?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; class CreateUsersRolesTable extends Migration { public function up() { Schema::create('users_roles', function (Blueprint $table) { $table->unsignedBigInteger('user_id'); $table->unsignedBigInteger('role_id'); //FOREIGN KEY CONSTRAINTS $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); $table->foreign('role_id')->references('id')->on('roles')->onDelete('cascade'); //SETTING THE PRIMARY KEYS $table->primary(['user_id','role_id']); }); } public function down() { Schema::dropIfExists('users_roles'); } } جدول roles_permissions: <?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; class CreateRolesPermissionsTable extends Migration { public function up() { Schema::create('roles_permissions', function (Blueprint $table) { $table->unsignedBigInteger('role_id'); $table->unsignedBigInteger('permission_id'); //FOREIGN KEY CONSTRAINTS $table->foreign('role_id')->references('id')->on('roles')->onDelete('cascade'); $table->foreign('permission_id')->references('id')->on('permissions')->onDelete('cascade'); //SETTING THE PRIMARY KEYS $table->primary(['role_id','permission_id']); }); } public function down() { Schema::dropIfExists('roles_permissions'); } } نقوم بعملية التهجير: php artisan migrate إنشاء العلاقات بين النماذج علاقات النموذج Role: public function permissions() { return $this->belongsToMany(Permission::class,'roles_permissions'); } public function users() { return $this->belongsToMany(User::class,'users_roles'); } علاقات النموذج Permission: public function roles() { return $this->belongsToMany(Role::class,'roles_permissions'); } public function users() { return $this->belongsToMany(User::class,'users_permissions'); } إنشاء Trait لإستخدامه في النموذج User، في مٌجلد app نقوم بإنشاء مُجلد Permissions و نضع بداخله ملف HasPermissionsTrait.php ثم نقوم بتضمينه داخل النموذج User: <?php namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Notifications\Notifiable; use App\Permissions\HasPermissionsTrait; class User extends Authenticatable { use HasFactory, Notifiable, HasPermissionsTrait; } يكون مُحتوى الملف HasPermissionsTrait بالشكل التالي: <?php namespace App\Permissions; use App\Models\Permission; use App\Models\Role; 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('slug', $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('slug', $permission->slug)->count(); } protected function getAllPermissions(array $permissions) { return Permission::whereIn('slug',$permissions)->get(); } } إنشاء مُزود خدمة PermissionsServiceProvider: php artisan make:provider PermissionsServiceProvider نقوم بإضافة blade directive فيه و تعريف بوابة Gate من أجل كل صلاحية في الدالة boot: <?php namespace App\Providers; use App\Models\Permission; use Illuminate\Support\Facades\Blade; use Illuminate\Support\Facades\Gate; use Illuminate\Support\ServiceProvider; class PermissionsServiceProvider extends ServiceProvider { public function register() { // } public function boot() { try { Permission::get()->map(function ($permission) { Gate::define($permission->slug, function ($user) use ($permission) { return $user->hasPermissionTo($permission); }); }); } catch (\Exception $e) { report($e); return false; } //Blade directives Blade::directive('role', function ($role) { return "if(auth()->check() && auth()->user()->hasRole({$role})) :"; //return this if statement inside php tag }); Blade::directive('endrole', function ($role) { return "endif;"; //return this endif statement inside php tag }); } } بعد ذلك نقوم بتسجيل مُزود الخدمة في مصفوفة providers في الملف config\app.php: 'providers' => [ App\Providers\PermissionsServiceProvider::class, ], الآن تحتاج إلا إضافة بعض البيانات الإختبارية ملف بذر لكل من الصلاحيات و الأدوار و تضع فيه كل صلاحيات الموقع و بعض الأدوار التي تريد أن تكون ضمن تطبيقك و تربط الصلاحيات بالأدوار ثم تربط الأدوار بالمُستخدمين. <?php $admin_permission = Permission::where('slug','create-users')->first(); $manager_permission = Permission::where('slug', 'edit-users')->first(); //RoleTableSeeder.php $admin_role = new Role(); $admin_role->slug = 'admin'; $admin_role->name = 'Admin Role'; $admin_role->save(); $admin_role->permissions()->attach($admin_permission); $manager_role = new Role(); $manager_role->slug = 'manager'; $manager_role->name = 'Assistant Manager'; $manager_role->save(); $manager_role->permissions()->attach($manager_permission); $admin_role = Role::where('slug','admin')->first(); $manager_role = Role::where('slug', 'manager')->first(); $createUsers = new Permission(); $createUsers->slug = 'create-users'; $createUsers->name = 'Create Users'; $createUsers->save(); $createUsers->roles()->attach($admin_role); $editUsers = new Permission(); $editUsers->slug = 'edit-users'; $editUsers->name = 'Edit Users'; $editUsers->save(); $editUsers->roles()->attach($manager_role); $admin_role = Role::where('slug','admin')->first(); $manager_role = Role::where('slug', 'manager')->first(); $admin_perm = Permission::where('slug','create-users')->first(); $manager_perm = Permission::where('slug','edit-users')->first(); $admin = new User(); $admin->name = 'Samir Abboud'; $admin->email = 'samir@gmail.com'; $admin->password = bcrypt('password'); $admin->save(); $admin->roles()->attach($admin_role); $admin->permissions()->attach($admin_perm); $manager = new User(); $manager->name = 'Kamel Mahmoudi'; $manager->email = 'kamel@gmail.com'; $manager->password = bcrypt('password'); $manager->save(); $manager->roles()->attach($manager_role); $manager->permissions()->attach($manager_perm); يُمكنك إستخدام tinker لعمل test: $admin = User::where('email', 'samir@gmail.com')->first(); $admin->hasRole('admin'); // لفحص إن كان المُستخدم يملك الدور مدير $admin->givePermissionsTo('edit-users') // إعطاء المُستخدم صلاحية تعديل مُستخدمين $admin->can('create-users') // فحص المُستخدم إذا كان لديه صلاحية إنشاء مُستخدم في صفحات العرض يُمكن إستخدام التوجيه الذي أنشأناه: @role('admin') مرحبا مدير @endrole الخطوة الأخيرة هي إنشاء middleware لعدم السماح للمُستخدم الوصول إلى مسار مُحدد إذا لم يكن يملك الصلاحية: php artisan make:middleware RoleMiddleware php artisan make:middleware PermissionMiddleware <?php namespace App\Http\Middleware; use Closure; class RoleMiddleware { public function handle($request, Closure $next, $role) { if (!auth()->check()) { return redirect()->route('login'); } if(!auth()->user()->hasRole($role)) { abort(403); } return $next($request); } } <?php namespace App\Http\Middleware; use Closure; class PermissionMiddleware { public function handle($request, Closure $next, $permission) { if (!auth()->check()) { return redirect()->route('login'); } if(!auth()->user()->can($permission)) { abort(403); } return $next($request); } } بعد ذلك تقوم بتسجيل هاتين الmiddleware ضمن App\Http\Kernel.php في مصفوفة routeMiddleware: <?php protected $routeMiddleware = [ . . 'role' => \App\Http\Middleware\RoleMiddleware::class, 'permission' => \App\Http\Middleware\PermissionMiddleware::class, ]; الآن يتبقى فقط الإستخدام في ملف المسارات: <?php Route::group(['middleware' => 'role:admin'], function() { // مسارات المُستخدم الذي يملك الدور مدير }); أو من خلال باني المُتحكم: public function __construct() { $this->middleware('permission:create-users')->only(['create', 'store']); } إن كنت ستستخدم حزمة جاهزة فستجد كل هذه الخصائص موجودة فيها و ستجدها قد تم إختبارها بإستعمال الإختبارات الأحادية أيضاً. 2 اقتباس
السؤال
Mahmoud Alrashidi
كيف يُمكن إنشاء مُستخدمين و تقسيمهم حسب صلاحيات مُحددة، مثلاً إنشاء مُستخدمين لهم دور مدير و مستخدمين لهم دور مٌحاسب في النظام مع تحديد صلاحيات المُحاسب و مُستخدمين عاديين ... الخ
3 أجوبة على هذا السؤال
Recommended Posts
انضم إلى النقاش
يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.