نسخه:

میان افزار

معرفی

Middleware مکانیزم مناسبی را برای بازرسی و فیلتر کردن درخواست‌های HTTP که وارد برنامه شما می‌شوند فراهم می‌کند. به عنوان مثال، لاراول شامل یک میان افزار است که تأیید می کند کاربر برنامه شما احراز هویت شده است. اگر کاربر احراز هویت نشده باشد، میان افزار کاربر را به صفحه ورود به سیستم برنامه شما هدایت می کند. با این حال، اگر کاربر احراز هویت شود، میان‌افزار به درخواست اجازه می‌دهد تا در برنامه ادامه یابد.

میان‌افزار اضافی را می‌توان برای انجام کارهای مختلف علاوه بر احراز هویت نوشت. به عنوان مثال، یک میان افزار لاگ ممکن است تمام درخواست های دریافتی را به برنامه شما ثبت کند. انواع میان‌افزار در لاراول گنجانده شده است، از جمله میان‌افزار برای احراز هویت و حفاظت CSRF. با این حال، همه میان افزارهای تعریف شده توسط کاربر معمولاً در app/Http/Middleware فهرست برنامه شما قرار دارند.

تعریف میان افزار

برای ایجاد یک میان افزار جدید، از make:middleware دستور Artisan استفاده کنید:

php artisan make:middleware EnsureTokenIsValid

EnsureTokenIsValid این دستور یک کلاس جدید را در دایرکتوری شما قرار می دهد app/Http/Middleware . در این میان افزار، تنها در صورتی اجازه دسترسی به مسیر را می دهیم که token ورودی ارائه شده با مقدار مشخصی مطابقت داشته باشد. در غیر این صورت، کاربران را به URI هدایت خواهیم کرد home :

<?php
 
namespace App\Http\Middleware;
 
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
 
class EnsureTokenIsValid
{
/**
* Handle an incoming request.
*
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
*/
public function handle(Request $request, Closure $next): Response
{
if ($request->input('token') !== 'my-secret-token') {
return redirect('home');
}
 
return $next($request);
}
}

همانطور که می بینید، اگر داده شده با token توکن مخفی ما مطابقت نداشته باشد، میان افزار یک تغییر مسیر HTTP را به مشتری برمی گرداند. در غیر این صورت، درخواست بیشتر به برنامه ارسال می شود. برای ارسال درخواست عمیق تر به برنامه (اجازه دادن به میان افزار برای "عبور")، باید $next با استفاده از $request .

بهتر است میان‌افزار را به‌عنوان یک سری از درخواست‌های HTTP «لایه‌ها» تصور کنید که قبل از ورود به برنامه شما باید از آن عبور کنند. هر لایه می تواند درخواست را بررسی کند و حتی آن را به طور کامل رد کند.

همه میان‌افزارها از طریق کانتینر سرویس حل می‌شوند ، بنابراین می‌توانید وابستگی‌هایی را که در سازنده میان‌افزار نیاز دارید تایپ کنید.

میان افزار و پاسخ ها

البته، یک میان‌افزار می‌تواند وظایفی را قبل یا بعد از ارسال درخواست به عمق برنامه انجام دهد. به عنوان مثال، میان افزار زیر برخی از وظایف را قبل از رسیدگی به درخواست توسط برنامه انجام می دهد:

<?php
 
namespace App\Http\Middleware;
 
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
 
class BeforeMiddleware
{
public function handle(Request $request, Closure $next): Response
{
// Perform action
 
return $next($request);
}
}

با این حال، این میان افزار پس از رسیدگی به درخواست توسط برنامه، وظیفه خود را انجام می دهد:

<?php
 
namespace App\Http\Middleware;
 
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
 
class AfterMiddleware
{
public function handle(Request $request, Closure $next): Response
{
$response = $next($request);
 
// Perform action
 
return $response;
}
}

ثبت نرم افزار میانی

میان افزار جهانی

اگر می خواهید یک میان افزار در طول هر درخواست HTTP برای برنامه شما اجرا شود، می توانید آن را به پشته میان افزار جهانی در bootstrap/app.php فایل برنامه خود اضافه کنید:

use App\Http\Middleware\EnsureTokenIsValid;
 
->withMiddleware(function (Middleware $middleware) {
$middleware->append(EnsureTokenIsValid::class);
})

شی $middleware ارائه شده به withMiddleware بسته شدن نمونه ای از Illuminate\Foundation\Configuration\Middleware و مسئول مدیریت میان افزار اختصاص داده شده به مسیرهای برنامه شما است. این append روش میان افزار را به انتهای لیست میان افزارهای جهانی اضافه می کند. اگر می خواهید یک میان افزار به ابتدای لیست اضافه کنید، باید از prepend روش استفاده کنید.

مدیریت دستی میان افزار جهانی پیش فرض لاراول

اگر می‌خواهید پشته میان‌افزار جهانی لاراول را به صورت دستی مدیریت کنید، می‌توانید پشته میان‌افزار جهانی لاراول پیش‌فرض را به روش ارائه دهید use . سپس، می‌توانید پشته میان‌افزار پیش‌فرض را در صورت لزوم تنظیم کنید:

->withMiddleware(function (Middleware $middleware) {
$middleware->use([
// \Illuminate\Http\Middleware\TrustHosts::class,
\Illuminate\Http\Middleware\TrustProxies::class,
\Illuminate\Http\Middleware\HandleCors::class,
\Illuminate\Foundation\Http\Middleware\PreventRequestsDuringMaintenance::class,
\Illuminate\Http\Middleware\ValidatePostSize::class,
\Illuminate\Foundation\Http\Middleware\TrimStrings::class,
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
]);
})

اختصاص نرم افزار میانی به مسیرها

اگر می‌خواهید میان‌افزار را به مسیرهای خاصی اختصاص دهید، می‌توانید middleware هنگام تعریف مسیر از روش استفاده کنید:

use App\Http\Middleware\EnsureTokenIsValid;
 
Route::get('/profile', function () {
// ...
})->middleware(EnsureTokenIsValid::class);

می‌توانید با ارسال آرایه‌ای از نام‌های میان‌افزار به middleware روش، چند میان‌افزار را به مسیر اختصاص دهید:

Route::get('/', function () {
// ...
})->middleware([First::class, Second::class]);

به استثنای میان افزار

هنگامی که میان‌افزار را به گروهی از مسیرها اختصاص می‌دهید، ممکن است گاهی لازم باشد از اعمال میان‌افزار به یک مسیر جداگانه در گروه جلوگیری کنید. شما می توانید این کار را با استفاده از withoutMiddleware روش زیر انجام دهید:

use App\Http\Middleware\EnsureTokenIsValid;
 
Route::middleware([EnsureTokenIsValid::class])->group(function () {
Route::get('/', function () {
// ...
});
 
Route::get('/profile', function () {
// ...
})->withoutMiddleware([EnsureTokenIsValid::class]);
});

همچنین می‌توانید مجموعه معینی از میان‌افزار را از کل گروهی از تعاریف مسیر حذف کنید:

use App\Http\Middleware\EnsureTokenIsValid;
 
Route::withoutMiddleware([EnsureTokenIsValid::class])->group(function () {
Route::get('/profile', function () {
// ...
});
});

این روش فقط می تواند میان افزار مسیر را حذف کند و برای میان افزار جهانی withoutMiddleware اعمال نمی شود .

گروه های میان افزار

گاهی اوقات ممکن است بخواهید چندین میان افزار را زیر یک کلید گروه بندی کنید تا تخصیص آنها به مسیرها آسان تر شود. می توانید این کار را با استفاده از appendToGroup روش موجود در فایل برنامه خود انجام دهید bootstrap/app.php :

use App\Http\Middleware\First;
use App\Http\Middleware\Second;
 
->withMiddleware(function (Middleware $middleware) {
$middleware->appendToGroup('group-name', [
First::class,
Second::class,
]);
 
$middleware->prependToGroup('group-name', [
First::class,
Second::class,
]);
})

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

Route::get('/', function () {
// ...
})->middleware('group-name');
 
Route::middleware(['group-name'])->group(function () {
// ...
});

گروه های میان افزار پیش فرض لاراول

لاراول شامل گروه‌های از پیش تعریف‌شده web و api میان‌افزاری است که حاوی میان‌افزار رایجی هستند که ممکن است بخواهید در مسیرهای وب و API خود اعمال کنید. به یاد داشته باشید، لاراول به طور خودکار این گروه های میان افزاری را در فایل ها routes/web.php و فایل های مربوطه اعمال می کند routes/api.php :

گروه web میان افزار
Illuminate\Cookie\Middleware\EncryptCookies
Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse
Illuminate\Session\Middleware\StartSession
Illuminate\View\Middleware\ShareErrorsFromSession
Illuminate\Foundation\Http\Middleware\ValidateCsrfToken
Illuminate\Routing\Middleware\SubstituteBindings
گروه api میان افزار
Illuminate\Routing\Middleware\SubstituteBindings

اگر می‌خواهید میان‌افزار را به این گروه‌ها اضافه یا اضافه کنید، می‌توانید از روش‌های web و api در فایل برنامه خود استفاده کنید bootstrap/app.php . و روش web ها api جایگزین مناسبی برای appendToGroup روش هستند:

use App\Http\Middleware\EnsureTokenIsValid;
use App\Http\Middleware\EnsureUserIsSubscribed;
 
->withMiddleware(function (Middleware $middleware) {
$middleware->web(append: [
EnsureUserIsSubscribed::class,
]);
 
$middleware->api(prepend: [
EnsureTokenIsValid::class,
]);
})

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

use App\Http\Middleware\StartCustomSession;
use Illuminate\Session\Middleware\StartSession;
 
$middleware->web(replace: [
StartSession::class => StartCustomSession::class,
]);

یا، می توانید یک میان افزار را به طور کامل حذف کنید:

$middleware->web(remove: [
StartSession::class,
]);

مدیریت دستی گروه های میان افزار پیش فرض لاراول

اگر می‌خواهید به صورت دستی تمام میان‌افزارها را در گروه‌های پیش‌فرض web و api میان‌افزار لاراول مدیریت کنید، می‌توانید گروه‌ها را به طور کامل دوباره تعریف کنید. مثال زیر گروه‌های میان‌افزار web و api میان‌افزار را با میان‌افزار پیش‌فرضشان تعریف می‌کند و به شما امکان می‌دهد در صورت لزوم آن‌ها را سفارشی کنید:

->withMiddleware(function (Middleware $middleware) {
$middleware->group('web', [
\Illuminate\Cookie\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\Illuminate\Foundation\Http\Middleware\ValidateCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
// \Illuminate\Session\Middleware\AuthenticateSession::class,
]);
 
$middleware->group('api', [
// \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
// 'throttle:api',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
]);
})

به طور پیش‌فرض، گروه‌های میان‌افزار web و میان‌افزار به‌طور خودکار بر روی فایل‌های مربوطه و فایل‌های api برنامه شما اعمال می‌شوند . routes/web.php routes/api.php bootstrap/app.php

نام مستعار میان افزار

شما می توانید نام مستعار را به میان افزار در فایل برنامه خود اختصاص دهید bootstrap/app.php . نام مستعار میان‌افزار به شما امکان می‌دهد یک نام مستعار کوتاه برای یک کلاس میان‌افزار معین تعریف کنید، که می‌تواند به ویژه برای میان‌افزار با نام‌های کلاس طولانی مفید باشد:

use App\Http\Middleware\EnsureUserIsSubscribed;
 
->withMiddleware(function (Middleware $middleware) {
$middleware->alias([
'subscribed' => EnsureUserIsSubscribed::class
]);
})

هنگامی که نام مستعار میان‌افزار در فایل برنامه شما تعریف شد bootstrap/app.php ، می‌توانید هنگام اختصاص دادن میان‌افزار به مسیرها از نام مستعار استفاده کنید:

Route::get('/profile', function () {
// ...
})->middleware('subscribed');

برای راحتی، برخی از میان افزارهای داخلی لاراول به طور پیش فرض نام مستعار دارند. به عنوان مثال، auth میان افزار نام مستعار Illuminate\Auth\Middleware\Authenticate میان افزار است. در زیر لیستی از نام مستعار میان افزار پیش فرض آمده است:

نام مستعار میان افزار
auth Illuminate\Auth\Middleware\Authenticate
auth.basic Illuminate\Auth\Middleware\AuthenticateWithBasicAuth
auth.session Illuminate\Session\Middleware\AuthenticateSession
cache.headers Illuminate\Http\Middleware\SetCacheHeaders
can Illuminate\Auth\Middleware\Authorize
guest Illuminate\Auth\Middleware\RedirectIfAuthenticated
password.confirm Illuminate\Auth\Middleware\RequirePassword
precognitive Illuminate\Foundation\Http\Middleware\HandlePrecognitiveRequests
signed Illuminate\Routing\Middleware\ValidateSignature
subscribed \Spark\Http\Middleware\VerifyBillableIsSubscribed
throttle Illuminate\Routing\Middleware\ThrottleRequests یا Illuminate\Routing\Middleware\ThrottleRequestsWithRedis
verified Illuminate\Auth\Middleware\EnsureEmailIsVerified

مرتب سازی میان افزارها

به ندرت، ممکن است نیاز داشته باشید که میان افزار خود را با یک ترتیب خاص اجرا کنید، اما زمانی که به مسیر اختصاص داده می شود، کنترلی بر ترتیب آنها نداشته باشید. در این شرایط، می توانید اولویت میان افزار خود را با استفاده از priority روش موجود در فایل برنامه خود مشخص کنید bootstrap/app.php :

->withMiddleware(function (Middleware $middleware) {
$middleware->priority([
\Illuminate\Foundation\Http\Middleware\HandlePrecognitiveRequests::class,
\Illuminate\Cookie\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\Illuminate\Foundation\Http\Middleware\ValidateCsrfToken::class,
\Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
\Illuminate\Routing\Middleware\ThrottleRequests::class,
\Illuminate\Routing\Middleware\ThrottleRequestsWithRedis::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
\Illuminate\Contracts\Auth\Middleware\AuthenticatesRequests::class,
\Illuminate\Auth\Middleware\Authorize::class,
]);
})

پارامترهای میان افزار

میان افزار همچنین می تواند پارامترهای اضافی را دریافت کند. به عنوان مثال، اگر برنامه شما باید قبل از انجام یک عمل مشخص، تأیید کند که کاربر تأیید شده دارای یک "نقش" است، می توانید یک EnsureUserHasRole میان افزار ایجاد کنید که یک نام نقش را به عنوان یک آرگومان اضافی دریافت کند.

پارامترهای میان‌افزار اضافی پس از آرگومان به میان‌افزار ارسال می‌شوند $next :

<?php
 
namespace App\Http\Middleware;
 
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
 
class EnsureUserHasRole
{
/**
* Handle an incoming request.
*
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
*/
public function handle(Request $request, Closure $next, string $role): Response
{
if (! $request->user()->hasRole($role)) {
// Redirect...
}
 
return $next($request);
}
 
}

پارامترهای میان‌افزار ممکن است هنگام تعریف مسیر با جدا کردن نام میان‌افزار و پارامترها با علامت زیر مشخص شوند : :

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

ممکن است چندین پارامتر با کاما مشخص شوند:

Route::put('/post/{id}', function (string $id) {
// ...
})->middleware('role:editor,publisher');

میان افزار پایان پذیر

گاهی اوقات ممکن است پس از ارسال پاسخ HTTP به مرورگر، یک میان افزار نیاز به انجام برخی کارها داشته باشد. اگر روشی را در میان افزار خود تعریف کنید terminate و سرور وب شما از FastCGI استفاده می کند، terminate پس از ارسال پاسخ به مرورگر، روش به طور خودکار فراخوانی می شود:

<?php
 
namespace Illuminate\Session\Middleware;
 
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
 
class TerminatingMiddleware
{
/**
* Handle an incoming request.
*
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
*/
public function handle(Request $request, Closure $next): Response
{
return $next($request);
}
 
/**
* Handle tasks after the response has been sent to the browser.
*/
public function terminate(Request $request, Response $response): void
{
// ...
}
}

متد terminate باید هم درخواست و هم پاسخ را دریافت کند. هنگامی که یک میان افزار پایان پذیر تعریف کردید، باید آن را به لیست مسیرها یا میان افزار جهانی در bootstrap/app.php فایل برنامه خود اضافه کنید.

هنگام فراخوانی terminate متد در میان‌افزار، لاراول یک نمونه جدید از میان‌افزار را از کانتینر سرویس حل می‌کند . اگر می‌خواهید هنگام فراخوانی متدهای handle و از همان نمونه میان‌افزار استفاده کنید terminate ، میان‌افزار را با استفاده از متد Container در Container ثبت کنید singleton . معمولاً این باید در register روش شما انجام شود AppServiceProvider :

use App\Http\Middleware\TerminatingMiddleware;
 
/**
* Register any application services.
*/
public function register(): void
{
$this->app->singleton(TerminatingMiddleware::class);
}