الفرق بين المراجعتين لصفحة: «Laravel/authorization»
رؤيا-بنعطية (نقاش | مساهمات) لا ملخص تعديل |
رؤيا-بنعطية (نقاش | مساهمات) لا ملخص تعديل |
||
(5 مراجعات متوسطة بواسطة نفس المستخدم غير معروضة) | |||
سطر 1: | سطر 1: | ||
<noinclude>{{DISPLAYTITLE:الترخيص في Laravel}}</noinclude> | <noinclude>{{DISPLAYTITLE:الترخيص (Authorization) في Laravel}}</noinclude> | ||
== | == مقدمة == | ||
بالإضافة إلى توفير خدمات الاستيثاق المضمنة بإطار العمل | بالإضافة إلى توفير خدمات الاستيثاق المضمنة بإطار العمل [[Laravel]]، يوفر [[Laravel]] أيضًا طريقة بسيطة لترخيص عمليات المستخدم على مورد معين. مثلما هو الحال مع الاستيثاق، فإن أسلوب [[Laravel]] للترخيص بسيط، وهناك طريقتان أساسيتان لترخيص العمليات: البوابات والسياسات (gates and policies). | ||
فكر في البوابات والسياسات مثل المسارات ووحدات التحكم. توفر البوابات أسلوبًا بسيطًا يعتمد على الإغلاق للترخيص، بينما تقوم السياسات، مثل وحدات التحكم، بتجميع منطقها حول نموذج معين أو مورد. سنستكشف البوابات أولاً ثم نفحص السياسات. | فكر في البوابات والسياسات مثل المسارات ووحدات التحكم. توفر البوابات أسلوبًا بسيطًا يعتمد على الإغلاق للترخيص، بينما تقوم السياسات، مثل وحدات التحكم، بتجميع منطقها حول نموذج معين أو مورد. سنستكشف البوابات أولاً ثم نفحص السياسات. | ||
سطر 10: | سطر 10: | ||
=== كتابة البوابات === | === كتابة البوابات === | ||
البوابات عبارة عن نطاقات مغلقة تحدد ما إذا كان المستخدم مرخصًا له لتنفيذ عملية معينة وتُعرَّف عادةً في صنف App\Providers\AuthServiceProvider باستخدام واجهة Gate. تتلقى البوابات دائمًا نسخة مستخدم كمعامل أول، وقد يتلقى اختياريًا مزيدًا من المعاملات مثل نموذج Eloquent ذي الصلة:<syntaxhighlight lang="php"> | البوابات عبارة عن نطاقات مغلقة تحدد ما إذا كان المستخدم مرخصًا له لتنفيذ عملية معينة وتُعرَّف عادةً في صنف <code>App\Providers\AuthServiceProvider</code> باستخدام واجهة Gate. تتلقى البوابات دائمًا نسخة مستخدم كمعامل أول، وقد يتلقى اختياريًا مزيدًا من المعاملات مثل نموذج [[Laravel/eloquent|Eloquent]] ذي الصلة:<syntaxhighlight lang="php"> | ||
/** | /** | ||
* تسجيل كل خدمات الاستيثاق/الترخيص | * تسجيل كل خدمات الاستيثاق/الترخيص | ||
* | * | ||
* @return void | * @return void | ||
*/ | */ | ||
public function boot() | public function boot() | ||
{ | { | ||
$this->registerPolicies(); | $this->registerPolicies(); | ||
Gate::define('update-post', function ($user, $post) { | Gate::define('update-post', function ($user, $post) { | ||
return $user->id == $post->user_id; | return $user->id == $post->user_id; | ||
}); | }); | ||
} | } | ||
سطر 38: | سطر 30: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
قد يتم أيضًا تعريف البوابات باستخدام أسلوب سلسلة نصية لردّ النداء Class@ | قد يتم أيضًا تعريف البوابات باستخدام أسلوب سلسلة نصية لردّ النداء <code>Class@method</code>، مثل وحدات التحكم:<syntaxhighlight lang="php"> | ||
/** | /** | ||
* تسجيل كل خدمات الاستيثاق/الترخيص. | * تسجيل كل خدمات الاستيثاق/الترخيص. | ||
* | * | ||
* @return void | * @return void | ||
*/ | */ | ||
سطر 52: | سطر 40: | ||
{ | { | ||
$this->registerPolicies(); | $this->registerPolicies(); | ||
Gate::define('update-post', 'PostPolicy@update'); | Gate::define('update-post', 'PostPolicy@update'); | ||
} | } | ||
سطر 62: | سطر 47: | ||
==== بوابات الموارد ==== | ==== بوابات الموارد ==== | ||
يمكنك أيضًا تحديد العديد من قدرات البوابة في وقت واحد باستخدام التابع resource:<syntaxhighlight lang="php"> | يمكنك أيضًا تحديد العديد من قدرات البوابة في وقت واحد باستخدام التابع <code>resource</code>:<syntaxhighlight lang="php"> | ||
Gate::resource('posts', 'App\Policies\PostPolicy'); | Gate::resource('posts', 'App\Policies\PostPolicy'); | ||
</syntaxhighlight> | </syntaxhighlight> | ||
سطر 68: | سطر 53: | ||
هذا مطابق للتعريف يدويًا بتعريفات البوابة التالية:<syntaxhighlight lang="php"> | هذا مطابق للتعريف يدويًا بتعريفات البوابة التالية:<syntaxhighlight lang="php"> | ||
Gate::define('posts.view', 'App\Policies\PostPolicy@view'); | Gate::define('posts.view', 'App\Policies\PostPolicy@view'); | ||
Gate::define('posts.create', 'App\Policies\PostPolicy@create'); | Gate::define('posts.create', 'App\Policies\PostPolicy@create'); | ||
Gate::define('posts.update', 'App\Policies\PostPolicy@update'); | Gate::define('posts.update', 'App\Policies\PostPolicy@update'); | ||
Gate::define('posts.delete', 'App\Policies\PostPolicy@delete'); | Gate::define('posts.delete', 'App\Policies\PostPolicy@delete'); | ||
</syntaxhighlight>ستعرف قدرات | </syntaxhighlight>ستعرف قدرات <code>view</code>، و <code>create</code>، و <code>update</code>، و <code>delete</code> تلقائيًا. يمكنك إعادة تعريف القدرات الافتراضية بتمرير مصفوفة كمعامل ثالث للتابع <code>resource</code>. تحدد مفاتيح المصفوفة أسماء القدرات بينما تحدد القيم أسماء التوابع. على سبيل المثال، ستُنشِئ التعليمة البرمجية التالية فقط تعريفين جديدين للبوابة - posts.image و posts.photo:<syntaxhighlight lang="php"> | ||
Gate::resource('posts', 'PostPolicy', [ | Gate::resource('posts', 'PostPolicy', [ | ||
'image' => 'updateImage', | 'image' => 'updateImage', | ||
'photo' => 'updatePhoto', | 'photo' => 'updatePhoto', | ||
سطر 88: | سطر 69: | ||
=== تفويض العمليات === | === تفويض العمليات === | ||
لترخيص عملية باستخدام البوابات، استخدم التابعين allows أو denies. لاحظ أنه لا يلزمك تمرير مستخدم الاستيثاق الحالي إلى هذين التابعين. سيُمرِّر Laravel المستخدم تلقائيًا إلى بوابة الإغلاق:<syntaxhighlight lang="php"> | لترخيص عملية باستخدام البوابات، استخدم التابعين <code>allows</code> أو <code>denies</code>. لاحظ أنه لا يلزمك تمرير مستخدم الاستيثاق الحالي إلى هذين التابعين. سيُمرِّر Laravel المستخدم تلقائيًا إلى بوابة الإغلاق:<syntaxhighlight lang="php"> | ||
if (Gate::allows('update-post', $post)) { | if (Gate::allows('update-post', $post)) { | ||
// المستخدم الحالي يستطيع تحديث المنشور... | // المستخدم الحالي يستطيع تحديث المنشور... | ||
سطر 96: | سطر 76: | ||
if (Gate::denies('update-post', $post)) { | if (Gate::denies('update-post', $post)) { | ||
// المستخدم الحالي لا يستطيع تحديث المنشور ... | // المستخدم الحالي لا يستطيع تحديث المنشور ... | ||
سطر 104: | سطر 83: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
إذا كنت ترغب في تحديد ما إذا كان هناك مستخدم معين مرخص له تنفيذ عملية ما، فيمكنك استخدام تابع forUser على واجهة البوابة:<syntaxhighlight lang="php"> | إذا كنت ترغب في تحديد ما إذا كان هناك مستخدم معين مرخص له تنفيذ عملية ما، فيمكنك استخدام تابع <code>forUser</code> على واجهة البوابة:<syntaxhighlight lang="php"> | ||
if (Gate::forUser($user)->allows('update-post', $post)) { | if (Gate::forUser($user)->allows('update-post', $post)) { | ||
// المستخدم يستطيع تحديث المنشور post... | |||
} | } | ||
if (Gate::forUser($user)->denies('update-post', $post)) { | if (Gate::forUser($user)->denies('update-post', $post)) { | ||
// المستخدم لا يستطيع تحديث المنشور post... | // المستخدم لا يستطيع تحديث المنشور post... | ||
سطر 125: | سطر 102: | ||
if ($user->isSuperAdmin()) { | if ($user->isSuperAdmin()) { | ||
return true; | return true; | ||
} | } | ||
سطر 149: | سطر 124: | ||
== إنشاء السياسات == | == إنشاء السياسات == | ||
=== | === توليد السياسات === | ||
السياسات هي تصنيفات تنظم منطق الترخيص حول نموذج أو مورد معين. على سبيل المثال، إذا كان تطبيقك عبارة عن مدونة، فقد يكون لديك نموذج منشور Post وسياسة PostPolicy مقابلة لترخيص عمليات المستخدم مثل إنشاء أو تحديث المنشورات. | السياسات هي تصنيفات تنظم منطق الترخيص حول نموذج أو مورد معين. على سبيل المثال، إذا كان تطبيقك عبارة عن مدونة، فقد يكون لديك نموذج منشور Post وسياسة PostPolicy مقابلة لترخيص عمليات المستخدم مثل إنشاء أو تحديث المنشورات. | ||
يمكنك إنشاء سياسة باستخدام الأمر <code>make:policy</code>. سيتم وضع السياسة التي تم إنشاؤها في المجلّد app/Policies. إذا كان هذا المجلد غير موجود في تطبيقك، سيقوم Laravel بإنشائه لك:<syntaxhighlight lang="php"> | يمكنك إنشاء سياسة باستخدام الأمر <code>make:policy</code>. سيتم وضع السياسة التي تم إنشاؤها في المجلّد <code>app/Policies</code>. إذا كان هذا المجلد غير موجود في تطبيقك، سيقوم [[Laravel]] بإنشائه لك:<syntaxhighlight lang="php"> | ||
php artisan make:policy PostPolicy | php artisan make:policy PostPolicy | ||
</syntaxhighlight> | </syntaxhighlight> | ||
سطر 160: | سطر 135: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
ملاحظة: يتم حل جميع السياسات عبر حاوي خدمات | ملاحظة: يتم حل جميع السياسات عبر حاوي خدمات [[Laravel]]، مما يسمح لك بالتلميح عن نوع (type-hint) أيّة اعتماديّات ضرورية في التابع الباني للسياسة لحقنها تلقائيًا. | ||
=== تسجيل السياسات === | === تسجيل السياسات === | ||
بمجرد وجود السياسة، يجب تسجيلها. يحتوي حاوي الخدمات AuthServiceProvider المضمن مع تطبيقات Laravel الجديدة على خاصية policies التي تربط نماذج Eloquent الخاصة بك مع سياساتها المقابلة. يخبر تسجيل سياسة Laravel بأي سياسة يستخدمها عند ترخيص العمليات على نموذج محدد:<syntaxhighlight lang="php"> | بمجرد وجود السياسة، يجب تسجيلها. يحتوي حاوي الخدمات <code>AuthServiceProvider</code> المضمن مع تطبيقات [[Laravel]] الجديدة على خاصية policies التي تربط نماذج Eloquent الخاصة بك مع سياساتها المقابلة. يخبر تسجيل سياسة [[Laravel]] بأي سياسة يستخدمها عند ترخيص العمليات على نموذج محدد:<syntaxhighlight lang="php"> | ||
<?php | <?php | ||
سطر 169: | سطر 144: | ||
use App\Post; | use App\Post; | ||
use App\Policies\PostPolicy; | use App\Policies\PostPolicy; | ||
use Illuminate\Support\Facades\Gate; | use Illuminate\Support\Facades\Gate; | ||
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider; | use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider; | ||
سطر 181: | سطر 153: | ||
/** | /** | ||
* تعيينات السياسة الخاصة بالتطبيق. | * تعيينات السياسة الخاصة بالتطبيق. | ||
* | * | ||
* @متغيير مصفوفة | * @متغيير مصفوفة | ||
*/ | */ | ||
سطر 193: | سطر 161: | ||
Post::class => PostPolicy::class, | Post::class => PostPolicy::class, | ||
]; | ]; | ||
/** | /** | ||
* سجل أيّ خدمات استيثاق / ترخيص خاصة بالتطبيق | * سجل أيّ خدمات استيثاق / ترخيص خاصة بالتطبيق | ||
* | * | ||
* @أرجع فراغ | * @أرجع فراغ | ||
*/ | */ | ||
سطر 209: | سطر 172: | ||
{ | { | ||
$this->registerPolicies(); | $this->registerPolicies(); | ||
// | // | ||
} | } | ||
}?> | }?> | ||
سطر 232: | سطر 192: | ||
use App\User; | use App\User; | ||
use App\Post; | use App\Post; | ||
سطر 240: | سطر 199: | ||
/** | /** | ||
* تحديد هل بإمكان المستخدم تحديث المنشور المعطى. | * تحديد هل بإمكان المستخدم تحديث المنشور المعطى. | ||
* | * | ||
* @param \App\User $user | * @param \App\User $user | ||
* @param \App\Post $post | * @param \App\Post $post | ||
* @return bool | * @return bool | ||
*/ | */ | ||
سطر 256: | سطر 209: | ||
{ | { | ||
return $user->id === $post->user_id; | return $user->id === $post->user_id; | ||
} | } | ||
} | } | ||
?> | ?> | ||
</syntaxhighlight> | </syntaxhighlight> | ||
سطر 275: | سطر 224: | ||
عند إنشاء توابع السياسة التي لن تتلقى نسخة عن النموذج، مثل تابع الإنشاء <code>create</code>، يجب إنشاء الدالة على أنها تتوقع المستخدم المسجّل دخول فقط:<syntaxhighlight lang="php"> | عند إنشاء توابع السياسة التي لن تتلقى نسخة عن النموذج، مثل تابع الإنشاء <code>create</code>، يجب إنشاء الدالة على أنها تتوقع المستخدم المسجّل دخول فقط:<syntaxhighlight lang="php"> | ||
/** | /** | ||
* تحديد ما إذا كان المستخدم المُعطى يمكنه إنشاء منشورات … | * تحديد ما إذا كان المستخدم المُعطى يمكنه إنشاء منشورات … | ||
* | * | ||
* @param \App\User $user | * @param \App\User $user | ||
* @return bool | * @return bool | ||
*/ | */ | ||
سطر 289: | سطر 233: | ||
{ | { | ||
// | // | ||
} | } | ||
سطر 302: | سطر 244: | ||
{ | { | ||
if ($user->isSuperAdmin()) { | if ($user->isSuperAdmin()) { | ||
return true; | return true; | ||
} | } | ||
} | } | ||
سطر 321: | سطر 259: | ||
=== عبر نموذج المستخدم === | === عبر نموذج المستخدم === | ||
يتضمن نموذج المستخدم المتضمن مع تطبيق Laravel تابعين مفيدين لترخيص العمليات: <code>can</code> و <code>cant</code>. يتلقى تابع <code>can</code> العملية التي ترغب في ترخيصها والنموذج ذا الصلة. على سبيل المثال ، دعنا نحدد ما إذا كان المستخدم مخولًا بتحديث نموذج منشور معين:<syntaxhighlight lang="php"> | يتضمن نموذج المستخدم المتضمن مع تطبيق [[Laravel]] تابعين مفيدين لترخيص العمليات: <code>can</code> و <code>cant</code>. يتلقى تابع <code>can</code> العملية التي ترغب في ترخيصها والنموذج ذا الصلة. على سبيل المثال ، دعنا نحدد ما إذا كان المستخدم مخولًا بتحديث نموذج منشور معين:<syntaxhighlight lang="php"> | ||
if ($user->can('update', $post)) { | if ($user->can('update', $post)) { | ||
سطر 332: | سطر 270: | ||
==== العمليات التي لا تتطلب نماذج ==== | ==== العمليات التي لا تتطلب نماذج ==== | ||
تذكر أن بعض العمليات مثل الإنشاء قد لا تتطلب نسخة عن النموذج. في هذه الحالات، يمكنك تمرير اسم الصنف إلى التابع can. سيستخدم اسم الصنف لتحديد السياسة التي ستستخدم عند ترخيص العملية:<syntaxhighlight lang="php"> | تذكر أن بعض العمليات مثل الإنشاء قد لا تتطلب نسخة عن النموذج. في هذه الحالات، يمكنك تمرير اسم الصنف إلى التابع <code>can</code>. سيستخدم اسم الصنف لتحديد السياسة التي ستستخدم عند ترخيص العملية:<syntaxhighlight lang="php"> | ||
use App\Post; | use App\Post; | ||
if ($user->can('create', Post::class)) { | if ($user->can('create', Post::class)) { | ||
// ينفذ التابع create على السياسات ذات الصلة | // ينفذ التابع create على السياسات ذات الصلة | ||
سطر 345: | سطر 282: | ||
=== عبر وسيط برمجي === | === عبر وسيط برمجي === | ||
يتضمن Laravel وسيطًا برمجيًا يمكنه ترخيص العمليات قبل أن يصل الاستعلام الوارد حتى إلى المسارات أو وحدات التحكم. بشكل افتراضي، يعين الوسيط Illuminate\Auth\Middleware\Authorize مفتاح التابع <code>can</code> في صنف App\Http\Kernel. دعنا نستكشف مثالًا على استخدام الوسيط البرمجي <code>can</code> لترخيص المستخدم لتحديث منشور المدونة:<syntaxhighlight lang="php"> | يتضمن Laravel وسيطًا برمجيًا يمكنه ترخيص العمليات قبل أن يصل الاستعلام الوارد حتى إلى المسارات أو وحدات التحكم. بشكل افتراضي، يعين الوسيط <code>Illuminate\Auth\Middleware\Authorize</code> مفتاح التابع <code>can</code> في صنف <code>App\Http\Kernel</code>. دعنا نستكشف مثالًا على استخدام الوسيط البرمجي <code>can</code> لترخيص المستخدم لتحديث منشور المدونة:<syntaxhighlight lang="php"> | ||
use App\Post; | use App\Post; | ||
Route::put('/post/{post}', function (Post $post) { | Route::put('/post/{post}', function (Post $post) { | ||
// المستخدم الحالي يمكنه تحديث المنشور... | // المستخدم الحالي يمكنه تحديث المنشور... | ||
سطر 355: | سطر 291: | ||
</syntaxhighlight>في هذا المثال، سنمرر معاملين للوسيط البرمجي <code>can</code>. الأول هو اسم العملية التي نرغب في ترخيصها، والثاني هو معامل المسار الذي نرغب في تمريره إلى تابع السياسة. في هذه الحالة، بما أننا نستخدم نموذج الربط الضمني implicit | </syntaxhighlight>في هذا المثال، سنمرر معاملين للوسيط البرمجي <code>can</code>. الأول هو اسم العملية التي نرغب في ترخيصها، والثاني هو معامل المسار الذي نرغب في تمريره إلى تابع السياسة. في هذه الحالة، بما أننا نستخدم نموذج الربط الضمني (implicit model binding)، فسيمرر نموذج post إلى تابع السياسة. إذا لم يكن المستخدم مرخصا لتنفيذ العملية المحدد، سينشئ الوسيط البرمجي استجابة HTTP برمز الحالة 403. | ||
==== العمليات التي لا تتطلب نماذج ==== | ==== العمليات التي لا تتطلب نماذج ==== | ||
سطر 369: | سطر 305: | ||
=== عبر مساعدي وحدة التحكم === | === عبر مساعدي وحدة التحكم === | ||
بالإضافة إلى التوابع المفيدة المقدمة لنموذج المستخدم، يوفر Laravel تابع ترخيص مفيد لأي من وحدات التحكم الخاصة بك والتي تعمل على توسيع الصنف الأساسي App\Http\Controllers\Controller. مثل تابع can، يقبل هذا التابع اسم العملية التي ترغب بالترخيص لها والنموذج ذي الصلة. إذا لم يتم الترخيص بهذه العملية، فسيقوم تابع الترخيص برمي الاستثناء Illuminate\Auth\Access\ | بالإضافة إلى التوابع المفيدة المقدمة لنموذج المستخدم، يوفر [[Laravel]] تابع ترخيص مفيد لأي من وحدات التحكم الخاصة بك والتي تعمل على توسيع الصنف الأساسي <code>App\Http\Controllers\Controller</code>. مثل تابع can، يقبل هذا التابع اسم العملية التي ترغب بالترخيص لها والنموذج ذي الصلة. إذا لم يتم الترخيص بهذه العملية، فسيقوم تابع الترخيص برمي الاستثناء <code>Illuminate\Auth\Access\AuthorizationException</code>، والذي سيحوله معالج الاستثناءات الافتراضي الخاص بـ [[Laravel]] إلى استجابة HTTP برمز الحالة 403:<syntaxhighlight lang="php"> | ||
namespace App\Http\Controllers; | namespace App\Http\Controllers; | ||
use App\Post; | use App\Post; | ||
use Illuminate\Http\Request; | use Illuminate\Http\Request; | ||
use App\Http\Controllers\Controller; | use App\Http\Controllers\Controller; | ||
سطر 381: | سطر 315: | ||
{ | { | ||
/** | /** | ||
*تحديث منشور المدونة المُعطى. | *تحديث منشور المدونة المُعطى. | ||
* | * | ||
* @param Request $request | * @param Request $request | ||
* @param Post $post | * @param Post $post | ||
* @return Response | * @return Response | ||
* @throws \Illuminate\Auth\Access\AuthorizationException | * @throws \Illuminate\Auth\Access\AuthorizationException | ||
*/ | */ | ||
public function update(Request $request, Post $post) | public function update(Request $request, Post $post) | ||
{ | { | ||
$this->authorize('update', $post); | $this->authorize('update', $post); | ||
// المستخدم الحالي يمكنه تحديث منشورات للمدونة... | // المستخدم الحالي يمكنه تحديث منشورات للمدونة... | ||
} | } | ||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
سطر 414: | سطر 335: | ||
كما تمت مناقشته سابقًا، قد لا تتطلب بعض العمليات مثل الإنشاء نسخة عن النموذج. في هذه الحالات، يمكنك تمرير اسم الصنف للتابع <code>authorize</code>. سيستخدم اسم الصنف لتحديد السياسة التي ستستخدم عند ترخيص العملية :<syntaxhighlight lang="php"> | كما تمت مناقشته سابقًا، قد لا تتطلب بعض العمليات مثل الإنشاء نسخة عن النموذج. في هذه الحالات، يمكنك تمرير اسم الصنف للتابع <code>authorize</code>. سيستخدم اسم الصنف لتحديد السياسة التي ستستخدم عند ترخيص العملية :<syntaxhighlight lang="php"> | ||
/** | /** | ||
* إنشاء منشور مدونة جديد. | * إنشاء منشور مدونة جديد. | ||
* | * | ||
* @param Request $request | * @param Request $request | ||
* @return Response | * @return Response | ||
* @throws \Illuminate\Auth\Access\AuthorizationException | * @throws \Illuminate\Auth\Access\AuthorizationException | ||
*/ | */ | ||
public function create(Request $request) | public function create(Request $request) | ||
{ | { | ||
$this->authorize('create', Post::class); | $this->authorize('create', Post::class); | ||
// المستخدم الحالي يمكنه انشاء منشورات للمدونة ... | // المستخدم الحالي يمكنه انشاء منشورات للمدونة ... | ||
} | } | ||
سطر 440: | سطر 351: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
=== عبر قالب Blade === | === عبر قالب [[Laravel/blade|Blade]] === | ||
عند كتابة قوالب | عند كتابة قوالب [[Laravel/blade|Blade]]، قد ترغب في عرض جزء من الصفحة فقط إذا كان المستخدم مرخّصًا لتنفيذ عملية ما. على سبيل المثال، قد ترغب في عرض نموذج محدث من منشور مدونة فقط إذا كان بإمكان المستخدم تحديث المنشور فعليًا. في هذه الحالة، يمكنك استخدام مجموعة الموجّهات <code>can</code> و<code>cannot</code>:<syntaxhighlight lang="xml"> | ||
@can('update', $post) | @can('update', $post) | ||
<!-- المستخدم الحالي يمكنه تحديث المنشور --> | <!-- المستخدم الحالي يمكنه تحديث المنشور --> | ||
سطر 479: | سطر 390: | ||
== مصادر == | == مصادر == | ||
* [https://laravel.com/docs/5.6/authorization صفحة Authorization في توثيق Laravel الرسمي.] | * [https://laravel.com/docs/5.6/authorization صفحة Authorization في توثيق Laravel الرسمي.] | ||
[[تصنيف:Laravel]] | [[تصنيف:Laravel|{{SUBPAGENAME}}]] | ||
[[تصنيف:Laravel Security]] | [[تصنيف:Laravel Security|{{SUBPAGENAME}}]] |
المراجعة الحالية بتاريخ 13:58، 24 أكتوبر 2018
مقدمة
بالإضافة إلى توفير خدمات الاستيثاق المضمنة بإطار العمل Laravel، يوفر Laravel أيضًا طريقة بسيطة لترخيص عمليات المستخدم على مورد معين. مثلما هو الحال مع الاستيثاق، فإن أسلوب Laravel للترخيص بسيط، وهناك طريقتان أساسيتان لترخيص العمليات: البوابات والسياسات (gates and policies).
فكر في البوابات والسياسات مثل المسارات ووحدات التحكم. توفر البوابات أسلوبًا بسيطًا يعتمد على الإغلاق للترخيص، بينما تقوم السياسات، مثل وحدات التحكم، بتجميع منطقها حول نموذج معين أو مورد. سنستكشف البوابات أولاً ثم نفحص السياسات.
لست بحاجة إلى الاختيار بين استخدام البوابات فقط أو استخدام السياسات فقط عند إنشاء تطبيق. على الأغلب تحتوي معظم التطبيقات على مزيج من البوابات والسياسات، وهذا مثالي تمامًا! تكون البوابات أكثر قابلية للتطبيق على العمليات التي لا تتعلق بأي نموذج أو مورد، مثل عرض لوحة تحكم المستخدمين ذوي الصلاحيّات الإداريّة. في المقابل، يجب أن تستخدم السياسات عندما ترغب في ترخيص عملية لنموذج أو مورد معين.
البوابات
كتابة البوابات
البوابات عبارة عن نطاقات مغلقة تحدد ما إذا كان المستخدم مرخصًا له لتنفيذ عملية معينة وتُعرَّف عادةً في صنف App\Providers\AuthServiceProvider
باستخدام واجهة Gate. تتلقى البوابات دائمًا نسخة مستخدم كمعامل أول، وقد يتلقى اختياريًا مزيدًا من المعاملات مثل نموذج Eloquent ذي الصلة:
/**
* تسجيل كل خدمات الاستيثاق/الترخيص
*
* @return void
*/
public function boot()
{
$this->registerPolicies();
Gate::define('update-post', function ($user, $post) {
return $user->id == $post->user_id;
});
}
قد يتم أيضًا تعريف البوابات باستخدام أسلوب سلسلة نصية لردّ النداء Class@method
، مثل وحدات التحكم:
/**
* تسجيل كل خدمات الاستيثاق/الترخيص.
*
* @return void
*/
public function boot()
{
$this->registerPolicies();
Gate::define('update-post', 'PostPolicy@update');
}
بوابات الموارد
يمكنك أيضًا تحديد العديد من قدرات البوابة في وقت واحد باستخدام التابع resource
:
Gate::resource('posts', 'App\Policies\PostPolicy');
هذا مطابق للتعريف يدويًا بتعريفات البوابة التالية:
Gate::define('posts.view', 'App\Policies\PostPolicy@view');
Gate::define('posts.create', 'App\Policies\PostPolicy@create');
Gate::define('posts.update', 'App\Policies\PostPolicy@update');
Gate::define('posts.delete', 'App\Policies\PostPolicy@delete');
ستعرف قدرات view
، و create
، و update
، و delete
تلقائيًا. يمكنك إعادة تعريف القدرات الافتراضية بتمرير مصفوفة كمعامل ثالث للتابع resource
. تحدد مفاتيح المصفوفة أسماء القدرات بينما تحدد القيم أسماء التوابع. على سبيل المثال، ستُنشِئ التعليمة البرمجية التالية فقط تعريفين جديدين للبوابة - posts.image و posts.photo:
Gate::resource('posts', 'PostPolicy', [
'image' => 'updateImage',
'photo' => 'updatePhoto',
]);
تفويض العمليات
لترخيص عملية باستخدام البوابات، استخدم التابعين allows
أو denies
. لاحظ أنه لا يلزمك تمرير مستخدم الاستيثاق الحالي إلى هذين التابعين. سيُمرِّر Laravel المستخدم تلقائيًا إلى بوابة الإغلاق:
if (Gate::allows('update-post', $post)) {
// المستخدم الحالي يستطيع تحديث المنشور...
}
if (Gate::denies('update-post', $post)) {
// المستخدم الحالي لا يستطيع تحديث المنشور ...
}
إذا كنت ترغب في تحديد ما إذا كان هناك مستخدم معين مرخص له تنفيذ عملية ما، فيمكنك استخدام تابع forUser
على واجهة البوابة:
if (Gate::forUser($user)->allows('update-post', $post)) {
// المستخدم يستطيع تحديث المنشور post...
}
if (Gate::forUser($user)->denies('update-post', $post)) {
// المستخدم لا يستطيع تحديث المنشور post...
}
اعتراض بوابة التحقيقات
في بعض الأحيان، قد ترغب في منح جميع القدرات لمستخدم معين. يمكن استخدام التابع before
لتعريف رد النداء الذي شغل قبل جميع عمليات التحقق من الترخيص الأخرى:
Gate::before(function ($user, $ability) {
if ($user->isSuperAdmin()) {
return true;
}
});
إذا كان رد نداء التابع before
يعيد نتيجة غير معدومة، سيتم اعتبار هذه النتيجة هي نتيجة التحقق.
يجوز لك استخدام التابع after
لتعريف رد النداء الذي يتم تشغيله بعد كل عملية تحقق من الترخيص:
ومع ذلك، لا يجوز لك تعديل نتيجة التحقق من الترخيص عبر رد نداء التابع after
:
Gate::after(function ($user, $ability, $result, $arguments) {
//
});
إنشاء السياسات
توليد السياسات
السياسات هي تصنيفات تنظم منطق الترخيص حول نموذج أو مورد معين. على سبيل المثال، إذا كان تطبيقك عبارة عن مدونة، فقد يكون لديك نموذج منشور Post وسياسة PostPolicy مقابلة لترخيص عمليات المستخدم مثل إنشاء أو تحديث المنشورات.
يمكنك إنشاء سياسة باستخدام الأمر make:policy
. سيتم وضع السياسة التي تم إنشاؤها في المجلّد app/Policies
. إذا كان هذا المجلد غير موجود في تطبيقك، سيقوم Laravel بإنشائه لك:
php artisan make:policy PostPolicy
سينشئ الأمر make:policy صنف سياسة فارغ. إذا كنت ترغب في إنشاء صنف يتضمن توابع السياسة الخاصة بالـ "CRUD"، فيمكنك تحديد --model عند تنفيذ الأمر:
php artisan make:policy PostPolicy --model=Post
ملاحظة: يتم حل جميع السياسات عبر حاوي خدمات Laravel، مما يسمح لك بالتلميح عن نوع (type-hint) أيّة اعتماديّات ضرورية في التابع الباني للسياسة لحقنها تلقائيًا.
تسجيل السياسات
بمجرد وجود السياسة، يجب تسجيلها. يحتوي حاوي الخدمات AuthServiceProvider
المضمن مع تطبيقات Laravel الجديدة على خاصية policies التي تربط نماذج Eloquent الخاصة بك مع سياساتها المقابلة. يخبر تسجيل سياسة Laravel بأي سياسة يستخدمها عند ترخيص العمليات على نموذج محدد:
<?php
namespace App\Providers;
use App\Post;
use App\Policies\PostPolicy;
use Illuminate\Support\Facades\Gate;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
class AuthServiceProvider extends ServiceProvider
{
/**
* تعيينات السياسة الخاصة بالتطبيق.
*
* @متغيير مصفوفة
*/
protected $policies = [
Post::class => PostPolicy::class,
];
/**
* سجل أيّ خدمات استيثاق / ترخيص خاصة بالتطبيق
*
* @أرجع فراغ
*/
public function boot()
{
$this->registerPolicies();
//
}
}?>
كتابة السياسات
توابع السياسة
بمجرد تسجيل السياسة، يمكنك إضافة توابع لكل عملية ترخصها. على سبيل المثال، دعنا نحدد تابع تحديث على سياسة PostPolicy الخاصة بنا، والتي تحدد ما إذا كان مستخدم معين يمكنه تحديث نسخة منشور معين.
يتلقى تابع التحديث النسختين المستخدم والمنشور كمعاملات، ويرجع القيمة true
أو false
والتي تشير إلى ما إذا كان المستخدم مرخصًا له بتحديث المنشور أم لا. لذلك، في هذا المثال، دعنا نتحقق من أن معرف المستخدم يطابق قيمة user_id في المنشور:
<?php
namespace App\Policies;
use App\User;
use App\Post;
class PostPolicy
{
/**
* تحديد هل بإمكان المستخدم تحديث المنشور المعطى.
*
* @param \App\User $user
* @param \App\Post $post
* @return bool
*/
public function update(User $user, Post $post)
{
return $user->id === $post->user_id;
}
}
?>
يمكنك الاستمرار في تعريف توابع إضافية للسياسة حسب الحاجة للعمليات المختلفة التي تأذن بها. على سبيل المثال، قد تقوم بتعريف توابع view
أو delete
لترخيص مختلف عمليات النشر، ولكن تذكر أنك حر في إعطاء أي اسم تريده لتوابع السياسة الخاصة بك.
ملاحظة: إذا استخدمت خاصية --model
عند إنشاء سياستك عبر وحدة التحكم Artisan، فستحتوي بالفعل على طرق للعرض وإنشاء وتحديث وحذف العمليات.
توابع بدون نماذج
لا تتلقى بعض توابع السياسة سوى المستخدم المسجّل دخول حاليًا وليس نسخة عن النموذج المرخص له. هذا الموقف أكثر شيوعًا عند ترخيص عمليات الإنشاء. على سبيل المثال، إذا كنت تقوم بإنشاء مدونة، فقد ترغب في التحقق مما إذا كان المستخدم مرخّصًا له بإنشاء أية منشورات على الإطلاق.
عند إنشاء توابع السياسة التي لن تتلقى نسخة عن النموذج، مثل تابع الإنشاء create
، يجب إنشاء الدالة على أنها تتوقع المستخدم المسجّل دخول فقط:
/**
* تحديد ما إذا كان المستخدم المُعطى يمكنه إنشاء منشورات …
*
* @param \App\User $user
* @return bool
*/
public function create(User $user)
{
//
}
مرشّحو السياسة
قد ترغب في ترخيص جميع العمليات ضمن سياسة معينة بالنسبة إلى بعض المستخدمين. لإنجاز هذا، عرف التابع before
في السياسة. سينفذ التابع before
قبل أي تابع آخر في السياسة، مما يتيح لك الفرصة لترخيص العملية قبل أن يتم استدعاء تابع السياسة المطلوب. تستخدم هذه الميزة بشكل شائع لترخيص مدراء التطبيق لتنفيذ أي عملية:
public function before($user, $ability)
{
if ($user->isSuperAdmin()) {
return true;
}
}
إذا كنت ترغب في رفض جميع الترخيصات للمستخدم، فيجب عليك إرجاع القيمة FALSE
من التابع before
. إذا رجعت القيمة null، فسيخضع الترخيص إلى طريقة السياسة.
تحذير: لن يستدعى التابع before
الخاص بصنف السياسة إذا لم يحتوي الصنف على تابع ذي اسم مطابق لاسم القدرة التي يتم التحقق منها.
ترخيص الإجراءات باستخدام السياسات
عبر نموذج المستخدم
يتضمن نموذج المستخدم المتضمن مع تطبيق Laravel تابعين مفيدين لترخيص العمليات: can
و cant
. يتلقى تابع can
العملية التي ترغب في ترخيصها والنموذج ذا الصلة. على سبيل المثال ، دعنا نحدد ما إذا كان المستخدم مخولًا بتحديث نموذج منشور معين:
if ($user->can('update', $post)) {
//
}
إذا سجلت سياسة للنموذج المحدد، فسيتصل التابع can
تلقائيًا بالسياسة المناسبة وإرجاع النتيجة المنطقية. إذا لم تكن هناك سياسة مسجلة للنموذج، فسيحاول التابع can
استدعاء النطاق المغلق للبوابة التي تطابق اسم العملية المحددة.
العمليات التي لا تتطلب نماذج
تذكر أن بعض العمليات مثل الإنشاء قد لا تتطلب نسخة عن النموذج. في هذه الحالات، يمكنك تمرير اسم الصنف إلى التابع can
. سيستخدم اسم الصنف لتحديد السياسة التي ستستخدم عند ترخيص العملية:
use App\Post;
if ($user->can('create', Post::class)) {
// ينفذ التابع create على السياسات ذات الصلة
}
عبر وسيط برمجي
يتضمن Laravel وسيطًا برمجيًا يمكنه ترخيص العمليات قبل أن يصل الاستعلام الوارد حتى إلى المسارات أو وحدات التحكم. بشكل افتراضي، يعين الوسيط Illuminate\Auth\Middleware\Authorize
مفتاح التابع can
في صنف App\Http\Kernel
. دعنا نستكشف مثالًا على استخدام الوسيط البرمجي can
لترخيص المستخدم لتحديث منشور المدونة:
use App\Post;
Route::put('/post/{post}', function (Post $post) {
// المستخدم الحالي يمكنه تحديث المنشور...
})->middleware('can:update,post');
في هذا المثال، سنمرر معاملين للوسيط البرمجي can
. الأول هو اسم العملية التي نرغب في ترخيصها، والثاني هو معامل المسار الذي نرغب في تمريره إلى تابع السياسة. في هذه الحالة، بما أننا نستخدم نموذج الربط الضمني (implicit model binding)، فسيمرر نموذج post إلى تابع السياسة. إذا لم يكن المستخدم مرخصا لتنفيذ العملية المحدد، سينشئ الوسيط البرمجي استجابة HTTP برمز الحالة 403.
العمليات التي لا تتطلب نماذج
مرة أخرى، قد لا تتطلب بعض العمليات مثل الإنشاء نسخة عن النموذج. في هذه الحالات، يمكنك تمرير اسم الصنف إلى الوسيط البرمجي. سيستخدم اسم الصنف لتحديد السياسة التي ستستخدم عند ترخيص العملية :
Route::post('/post', function () {
// المستخدم الحالي يمكنه كتابة منشورات...
})->middleware('can:create,App\Post');
عبر مساعدي وحدة التحكم
بالإضافة إلى التوابع المفيدة المقدمة لنموذج المستخدم، يوفر Laravel تابع ترخيص مفيد لأي من وحدات التحكم الخاصة بك والتي تعمل على توسيع الصنف الأساسي App\Http\Controllers\Controller
. مثل تابع can، يقبل هذا التابع اسم العملية التي ترغب بالترخيص لها والنموذج ذي الصلة. إذا لم يتم الترخيص بهذه العملية، فسيقوم تابع الترخيص برمي الاستثناء Illuminate\Auth\Access\AuthorizationException
، والذي سيحوله معالج الاستثناءات الافتراضي الخاص بـ Laravel إلى استجابة HTTP برمز الحالة 403:
namespace App\Http\Controllers;
use App\Post;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
class PostController extends Controller
{
/**
*تحديث منشور المدونة المُعطى.
*
* @param Request $request
* @param Post $post
* @return Response
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function update(Request $request, Post $post)
{
$this->authorize('update', $post);
// المستخدم الحالي يمكنه تحديث منشورات للمدونة...
}
}
العمليات التي لا تتطلب نماذج
كما تمت مناقشته سابقًا، قد لا تتطلب بعض العمليات مثل الإنشاء نسخة عن النموذج. في هذه الحالات، يمكنك تمرير اسم الصنف للتابع authorize
. سيستخدم اسم الصنف لتحديد السياسة التي ستستخدم عند ترخيص العملية :
/**
* إنشاء منشور مدونة جديد.
*
* @param Request $request
* @return Response
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function create(Request $request)
{
$this->authorize('create', Post::class);
// المستخدم الحالي يمكنه انشاء منشورات للمدونة ...
}
عبر قالب Blade
عند كتابة قوالب Blade، قد ترغب في عرض جزء من الصفحة فقط إذا كان المستخدم مرخّصًا لتنفيذ عملية ما. على سبيل المثال، قد ترغب في عرض نموذج محدث من منشور مدونة فقط إذا كان بإمكان المستخدم تحديث المنشور فعليًا. في هذه الحالة، يمكنك استخدام مجموعة الموجّهات can
وcannot
:
@can('update', $post)
<!-- المستخدم الحالي يمكنه تحديث المنشور -->
@elsecan('create', App\Post::class)
<!--المستخدم الحالي يمكنه إنشاء منشور جديد -->
@endcan
@cannot('update', $post)
<!-- المستخدم الحالي لا يمكنه تحديث المنشور -->
@elsecannot('create', App\Post::class)
<!- المستخدم الحالي لا يمكنه إنشاء منشور جديد-->
@endcannot
هذه الموجّهات هي اختصارات ملائمة لكتابة @if
وعبارات @unless
. إن عبارات can
وcannot
أعلاه تترجم إلى العبارات التالية بالترتيب:
@if (Auth::user()->can('update', $post))
<!-- المستخدم الحالي يمكنه تحديث المنشور -->
@endif
@unless (Auth::user()->can('update', $post))
<!-- المستخدم الحالي لا يمكنه تحديث المنشور -->
@endunless
العمليات التي لا تتطلب نماذج
مثل معظم دوال الترخيص الأخرى، يمكن تمرير اسم الصنف إلى توجيهات @can
و @cannot
إذا كانت العملية لا تتطلب نسخة عن النموذج:
@can('create', App\Post::class)
<!-- المستخدم الحالي يمكنه انشاء منشورات -->
@endcan
@cannot('create', App\Post::class)
<!-- المستخدم الحالي لا يمكنه انشاء منشورات -->
@endcannot