دانیال صناعی
دانیال صناعی
خواندن ۸ دقیقه·۳ سال پیش

مفهوم MiddleWare در لاراول به زبان ساده

میدل ویر ها در لاراول
میدل ویر ها در لاراول


مقدمه :

سلام دوستان دانیال هستم ، توسعه دهنده وب . امروز میخواییم با هم مفهوم Middleware بررسی کنیم و ببنیم Middleware توی لاراول چی کار میکنه و چطوری میتونه باعث بشه برنامه ما ایمن تر و حرفه ای تر بشه پس با من همراه باش !

میدل ویر چیه ؟؟

فرض کن الان میخوایی بری دبی ، خب بعد از رسیدن به دبی و یا هر کشور دیگه ای ، برای اینکه وارد خاک اون کشور بشی باید چندین مرحله بگذرونی . مرحله اول تست کرونا بدی ، مرحله دوم بارت چک میشه تا چیز غیر مجازی وارد نکنی ، مرحله سوم سابقت چک میشه ، مرحله چهارم پاسپورت و دلیل اومدنت به اون کشور چک میشه . بعد از این که همه این مراحل به ترتیب با موفقیت گذروندی ، میتونی وارد اون کشور بشی .

خب وجود هر کدوم از این مراحل برای داشتن کشوری ایمن ضروری هست ، هیچ کشوری دوس نداره افراد شرور و یا ناقل بیماری راه بده توی کشورش پس میاد و از این مراحل استفاده میکنه تا هر کسی وارد کشور میشه بررسی کنه و از وقوع مشکلات احتمالی جلوگیری کنه .

میدل ویر ها هم همین کار میکنند ، درخواست هایی که به سمت برنامه ما میانو اعتبار سنجی میکنند ، توی مثال بالا شمایی که میخوایی بری یه کشور خارجی میشی یه « درخواست » و هر کدوم از اون مراحلی که باید رد کنی تا وارد کشور بشی یه دونه « Middleware » هستند . در واقع MiddleWare ها یه لایه امنیتی هستند که نمیزارن هر درخواستی به هسته اصلی برنامه برسه !
Middleware
Middleware

لاراول یه تعدادی Middleware داره که به ما کمک میکنه درخواست هایی که به سمت برنامه میان به شیوه های مختلف پالایش کنیم ، و برنامه ای ایمن و کارا داشته باشیم . این Middleware ها توی قسمت app/http/middleware قابل مشاهده هستند .

همچنین این امکان در اختیار ما قرار داده که با توجه به برنامه ای که داریم میسازیم خودمون هم Middleware های اختصاصی بسازیم .

حالا چطوری یه Middleware درست کنیم ؟

فرض کنید داریم یه وبسایت امنیتی میسازیم ، که افرادی که خارج از ایران هستند توانایی دسترسی به این وبسایت نداشته باشن ینی این وبسایت فقط مخصوص ایرانی ها هستش ، خب همونطور که توضیح دادم این کار باید با استفاده از MiddleWare ها انجام بدیم ینی یه لایه محافظتی اضافه کنیم حالا چه طوری باید این کار انجام بدیم ؟

#ساخت MiddleWare مربوطه

php artisan make:middleware is_iran

وقتی که این دستور وارد میکنیم توی بخشapp/http/middleware یه کلاس جدید برامون درست میشه به اسم is_iran توی این کلاس یه متد وجود داره به اسم handle ، این متد میاد درخواستی که کاربر داده میگیره و بررسی های لازم روش انجام میده ، ( چک میکنه که کاربر از ایرانه یا نه ) و در آخر اگه همه چی اوکی بود میزاره کاربر از این مرحله رد بشه .

class is_iran { public function handle($request, Closure $next) { if ($request->getLocale()!='fa') { return response()->json('Site Is Not Open In Your Location'); } return $next($request); } }

آقا این return next ینی چی ؟

یه درخواست برای دسترسی به برنامه ممکنه نیاز باشه از چندین middleware بگذره ، مثلا یکی اینکه عضو سایت باشه ، یکی اینکه ایرانی باشه و سایر موارد . حالا این هر کدوم از این Middleware ها به شکل زنجیر وار به همدیگه وصل هستند . وقتی درخواست از یه Middleware با موفقیت میگذره با return $next به میدل ویر بعدی میره و وقتی همه Middleware ها رد کرد در مرحله آخر به اون Controller که کارای پردازشی انجام میده میرسه .

#ثبت کردن میدل ویر ها :

برای اینکه بتونیم از middleware هایی که ساختیم توی برناممون استفاده کنیم اول باید ثبتشون کنیم و به لاراول بگیم آقاجون از این به بعد فلان میدل ویر هم جز میدل ویرهات حساب کن . خب حالا چطوری این کار انجام بدیم ؟

ثبت کردن یه Middleware توی لاراول به سه شکل امکان پذیره که از هر کدومش در موقعیت مناسب خودش استفاده میکنیم این سه روش در ادامه گفتم .

#ثبت Middleware به شکل سراسری :

فرض کن میخواییم کل سایت و برنامه ما فقط مخصوص ایرانی ها باشه ، خب در این صورت باید میدل ویر is_iran به شکل سراسری ثبت کنیم تا با هر درخواستی که به سمت برنامه میاد اجرا بشه . برای اینکار هم باید بیاییم توی فایل app/http/kernel و آدرس میدل ویر is_iran به پراپرتی $middleware اضافه کنیم .

protected $middleware = [ \App\Http\Middleware\TrustProxies::class, \App\Http\Middleware\CheckForMaintenanceMode::class, \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class, \App\Http\Middleware\TrimStrings::class, \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class, is_iran::class, ];

خب حالا دیگه هر درخواستی به سمت سایت ارسال بشه میدل ویر is_iran راه میفته و چک میکنه طرف از ایران وارد شده یه نه اگر طرف از ایران نبود نمیزاره وارد سایت بشه و با ارور پایین مواجه میشه .

چون از ایران نیست  نمیزاره وارد بشه
چون از ایران نیست نمیزاره وارد بشه


ثبت میدل ویر برای روت ها :

اگر بخواییم یه middleware فقط برای یه سری روت خاص و نه همه روت های سایت اجرا بشه باید بیاییم آدرس اون middleware به پراپرتی routeMiddleware اضافه کنیم ، مثلا فرض کنید فقط قسمت هایی از سایتی که ما داریم برای خارجی ها بسته هست و بخش های زیادیش بازه . در این شرایط Middleware که برای بررسی موقعیت کاربر ساختیم ینی Is_Iran باید به پراپرتی routeMiddleware اضافه کنیم .

protected $routeMiddleware = [ 'auth' => \App\Http\Middleware\Authenticate::class, 'Admin' => \App\Http\Middleware\Admin::class, 'is_iran' => \App\Http\Middleware\is_iran::class, ];

حالا میتونیم توی هر روتی که بخواییم از is_iran استفاده کنیم و اون قسمت از سایت محدود کنیم :

Route::resource('/panel', 'Admin\panelController')->middleware('is_iran');

مثلا توی مثال بالا فقط افرادی میتونن به Panel دسترسی پیدا کنند که از میدل ویرis_iran عبور کرده باشند و ایرانی باشند ولی بقیه قسمت های سایت برای همه بازه و ربطی نداره که طرف ایرانی باشه یا نه .

البته اینم بگم که ()middleware<- میتونه تا بینهایت میدل ویر هم بگیره ینی ما برای یه روت هر چندتا Middleware که بخواییم میتونیم تعریف کنیم

Route::resource('/panel', 'Admin\panelController')->middleware('is_iran' ,'is_admin' ,'auth');

حالا بعضی دوستان هم هستند حال و حوصله ندارن اون میدل ویری که ساختنو توی routeMiddleware تعریف کنند و میان و مستقیم ازش استفاده میکنند :

Route::resource('/panel', 'Admin\panelController')->middleware(\App\Http\Middleware\is_iran::class);

البته این روش توصیه نمیشه ولی خوب به هر حال اینکارم میتونید بکنید .

#میدل ویر های گروهی :

همونطور که وقتی وارد یه کشور میشی از چندین مرحله یا Middleware باید عبور کنی ، برای اعتبار سنجی و پالایش یه درخواست هم ممکنه نیاز باشه چندین میدل ویر مورد استفاده قرار بدیم ، مثلا ۵ تا یا ۱۰ تا .

خب برای اینکه دیگه نیاییم اسم همه این میدل ویر ها دونه دونه بنویسیم میاییم میزاریمشون توی یه گروه و یه اسمی میزاریم براش . حالا دیگه هر جا خواستیم از این دسته میدل ویر ها استفاده کنیم میاییم اسم گروه مینویسیم .

مثلا فرض کنید برای این که وارد یه کشور بشید باید از 3 نظر اعتبار سنجی بشید :

چک کردن ویزا (Visa)

چک کردن بار (Bar)

چک کردن سابقه (Background)

پس الان اگه درخواستی مبنی بر ورود به کشور اومد به شکل زیر باید بنویسیمش :

Route::resource('/goToCountry', 'Admin\countryController')->middleware('visa','bar','background');

وقتی این درخواست ها زیاد بشه و ما مجبور باشیم از این سه تا میدل ویر توی روت های زیادی استفاده کنیم این که بیاییم هر بار به شکل بالا کد زنی کنیم صحیح نیست و بهتره که بیاییم این سه تا میدل ویر توی یه گروه بزاریم مثلا is_user_valid :

protected $middlewareGroups = [
'web' => [

],

'api' => [

],

'is_user_valid ' => [
\Illuminate\Session\Middleware\visa::class,
\Illuminate\Session\Middleware\bar::class,
\Illuminate\View\Middleware\background::class,
],
];

و روت هامون اینطوری بنویسیم :

Route::resource('/goToCountry', 'Admin\countryController')->middleware('is_user_valid');

# تافته جدا بافته در middleware ها

فرض کن یه گروهی از روت ها داری که یه middleware به همشون نسبت میدی مثلا auth ، حالا ممکنه که یکی از این روت ها به middleware به auth نیاز نداشته باشند ، مثلا الان فرض کن روت profile نیازمند میدل ویر auth نباشه برای اینکه روت profile از گروه خودش جدا نکنیم میاییم از متد withoutMiddleware استفاده میکنیم .

Route::middleware('auth')->group(function () {
Route::get('/', function () {
//
});

Route::get('/profile', function () {
//
})->withoutMiddleware('auth');
});

#مرتب سازی Middleware ها

بعضی وقتا که البته خیلی کم پیش میاد ممکنه نیاز بشه Middleware هامون بر اساس ترتیب خاصی اجرا بشن برای این که بتونیم ترتیب middleware هامون تغییر بدیم باید بیاییم توی middlewarePriority و ترتیب دلخواهمون بچینیم مثلا من اینجا اومدم گفتم is_iran زودتر از Authorize اجرا بشه :

protected $middlewarePriority = [
\Illuminate\Cookie\Middleware\EncryptCookies::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\Illuminate\Contracts\Auth\Middleware\AuthenticatesRequests::class,
\Illuminate\Routing\Middleware\ThrottleRequests::class,
\Illuminate\Session\Middleware\AuthenticateSession::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
is_iran::class
\Illuminate\Auth\Middleware\Authorize::class,
];

#پارامتر ها در Middleware ها :

جالب اینجاست که Middleware ها پارامتر هم میتونند دریافت کنند ، مثلا فرض کنید یه بخشی از سایتمون فقط برای بعضی از کاربران ثبت نام شده باز هست مثلا فقط ادمین ها ، ینی حتی اگر طرف ثبت نام کرده باشه ولی admin نباشه نمیتونه به اون روت دسترسی داشته باشه .

خب طبیعتا مرحله اول اینه که بیاییم یه Middleware بسازیم که این منطق برامون پیاده سازی کنه ینی بیاد با استفاده از Parameter نقشی که میتونه به این روت دستری پیدا کنه بگیره مثلا admin ، بعدش ببینه ایا اون کاربره این نقش داره یا نه !

<?php
class EnsureUserHasRole
{
public function handle($request, Closure $next, $role)
{
if (! $request->user()->hasRole($role)) {
// Redirect...
}
return $next($request);
}
}

خب حالا چطوری باید نقش به عنوان پارامتر به Middleware بدیم ؟

Route::put('/post/{id}', function ($id) {
//
})->middleware('role:admin');

خب دوستان مباحث مربوطه به Middleware ها من تمام و کمال گفتم اگه احساس میکنید جایی اشتباهی کردم یا خوب توضیح ندادم زیر همین پست برام کامنت کنید ، با تشکر از شما که همراه من بودید .

برنامه نویس فول استک وب
شاید از این پست‌ها خوشتان بیاید