توفیق حمزه‌ ئی
توفیق حمزه‌ ئی
خواندن ۱ دقیقه·۶ سال پیش

خطایی رایج در هنگام ساخت middleware سفارشی و راه حل آن

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

اررور ریدایرکت
اررور ریدایرکت


بگذارید در قالب یک مثال شرح دهم. اگر فقط میخواهید بدونید چرا این اررور رخ میدهد میتونید قسمت مثال رو نخونید.

مثال: کاربران بن شده

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

Schema::create('users', function (Blueprint $table) { $table->bigIncrements('id'); $table->string('name'); $table->string('email')->unique(); $table->timestamp('email_verified_at')->nullable(); $table->string('password'); $table->boolean('isBanned')->default(false); $table->rememberToken(); $table->timestamps(); });

خب حالا وقت ساخت یک middleware هست که کاربرانی که حسابشان مسدود شده رو ریدارکت بده. با دستور php artisan make:middleware ForbidBannedUser یک middleware میسازیم. حالا منطق middleware رو مینویسیم که چجوری ریدارکت بشه:

<?php namespace App\Http\Middleware; use Closure; use Illuminate\Contracts\Auth\Guard; class ForbidBannedUser { protected $auth; public function __construct(Guard $auth) { $this->auth = $auth; } /** * Handle an incoming request. * * @param \Illuminate\Http\Request $request * @param \Closure $next * @return mixed */ public function handle($request, Closure $next) { $user = $this->auth->user(); if ($user && $user->isBanned == 1) { return redirect('/login')->withInput()->withErrors([ 'email' => 'این حساب کاربری مسدود شده است.', ]); } return $next($request); } }

سپس middleware را در فایل App\Http\Kernel.php ثبت میکنیم:

protected $routeMiddleware = [ 'is-ban' => \App\Http\Middleware\ForbidBannedUser::class, ];

حالا نوبت به کار بردن middleware در روت هاست که به شکل زیر:

Route::group(['middleware' => 'is-ban'], function () { Route::get('/home', 'HomeController@index')->name('home'); // ... باقی روت ها });

حالا که ما در ادمین پنل حساب کاربر رو مسدود کردیم شاید متوجه تغییر نشیم ولی کاربری که حسابش مسدود شده وقتی که میخواد وارد سایت بشه به اررور زیر میخوره.

// Mozilla Firefox

The page isn’t redirecting properly


// chrome

This page isn’t working

127.0.0.1 redirected you too many times.

Try clearing your cookies.

ERR_TOO_MANY_REDIRECTS

حالا هر روتی که middleware is-ban رو داشته باشه دیگه قابل دسترسی نیست.


کلی ساعت و وقت میذارین ولی متوجه نمیشین چرا این اررور رخ داده. هرچند اررور خیلی واضح هست یعنی صفحه خیلی ریدارکت شده ولی زیرش نوشته ممکنه از کوکی ها باشه( که نیست)‌ و شما حتی شاید سعی کردین که کوکی ها رو پاک کنین.


چرا به این اررور میخوریم؟؟؟

علت اررور رو میدونیم. صفحه هی پشت سر هم ریدارکت میشه ولی چرا؟

در واقع بیشتر ما که با authentication دیفالت خود لاراول کار میکنیم باید بدونیم به جز middleware auth یک middleware دیگه به نام guest هم داریم:

روت ها
روت ها

همین جوری که میبینین اینجا تقریبا همه روت های authentication لاراول middleware guest رو دارن(جز logout). در واقع این middleware چک میکنه ایا شما به حساب کاربریتان وارد شده اید یا خیر؟‌ اگه وارد سایت شده اید شما رو به طور پیش فرض به روت home ریدایرکت میکنه(میتونین تغییر بدین).


حالا چی شد؟؟؟ ما در این کد ها جایی ننوشتیم که کاربر از حساب خارج بشه. پس یک حقله بی نهایت ساخته میشه. ما در روت home چک میکنیم که کاربر وارد شده مسدود حسابش مسدوده و ریدایرکت میدیم به روت login و اونجا هم middleware guest میبینه کاربر وارد سایت شده(کاربر لاگ اوت نشده)‌ و دوباره ریدایرکت میکنه به home و ... تا اررور redirected you too many times میده.


راه حل

از متن بالایی میشه فهمید با خارج کردن کاربر از سایت یعنی logout مشکل حل میشه. آن هم با یک خط:

auth()->logout(); // در مثال بالایی $this->auth->logout();

یعنی middleware ما به این صورت درمیاد:

<?php namespace App\Http\Middleware; use Closure; use Illuminate\Contracts\Auth\Guard; class ForbidBannedUser { protected $auth; public function __construct(Guard $auth) { $this->auth = $auth; } /** * Handle an incoming request. * * @param \Illuminate\Http\Request $request * @param \Closure $next * @return mixed */ public function handle($request, Closure $next) { $user = $this->auth->user(); if ($user && $user->isBanned == 1) { $this->auth->logout(); return redirect('login')->withInput()->withErrors([ 'email' => 'این حساب کاربری مسدود شده است.', ]); } return $next($request); } }

:)

برنامه نویسیلاراولlaravel
برنامه نویس :)
شاید از این پست‌ها خوشتان بیاید