Middleware

Middleware poskytuje pohodlný mechanismus pro filtrování HTTP požadavků vstupující do aplikace. Například Laravel poskytuje middleware, který ověřuje uživatele jestli jsou v aplikaci přihlášeni. Pokud nejsou, pak je middleware přesměruje na přihlašovací stránku. Naopak pokud jsou přihlášeni, middleware umožní požadavku pokračovat dále v aplikaci.

Kromě přihlašování mohou middleware vykonávat další řadu různých úkolů. CORS middleware může být zodpovědný za přidání správné hlavičky do odpovědi při opouštění naši aplikace. Middleware pro logování může zapisovat všechny požadavky, které aplikace obdrží apod.

Existuje několik middleware, které v Laravel framework již existují, například middleware pro přihlašování nebo CSRF ochranu. Všechny tyto middleware najdete v adresáři app/Http/Middleware.

Definování middleware

Pro vytvoření nového middleware použijte Artisan příkaz make:middleware:

php artisan make:middleware CheckAge

Tento příkaz vytvoří novou třídu CheckAge v adresáři app/Http/Middleware. V tomto middleware povolujeme přístup k routě pouze pokud parametr age je větší než 200. V opačném případě uživatele přesměrujeme zpět na URI home.

namespace App\Http\Middleware;

use Closure;

class CheckAge
{
    /**
     * Zachyceni pozadavku.
     *
     * @param  \Illuminate\Http\Request $request
     * @param  \Closure $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        if ($request->age <= 200) {
            return redirect('home');
        }

        return $next($request);
    }
}

Jak můžete vidět, pokud je age menší nebo stejné jak 200, pak middleware vrátí HTTP požadavek zpět klientovi. V opačném případě požadavek pokračuje dále v aplikaci . Pro pokračování požadavku hlouběji do aplikace(umožňující „projít“ skrze middleware), jednoduše zavolejte callback $next s parametrem $request.

Na middleware je nejlepší se dívat jako na vrstvy, kterými HTTP požadavky musí projít, než se dostanou k aplikaci. Každá vrstva může požadavek zpracovat nebo ho dokonce celý odmítnout.

Middleware před a po

Jestli se middleware vykoná před nebo po požadavku záleží na middleware samotném. Například následující middleware vykoná nějakou akci předtím než je požadavek zachycen aplikací:

namespace App\Http\Middleware;

use Closure;

class BeforeMiddleware
{
    public function handle($request, Closure $next)
    {
        // nejaka akce

        return $next($request);
    }
}

Nicméně tento middleware vykoná akci až potom co je požadavek zachycen aplikací:

namespace App\Http\Middleware;

use Closure;

class AfterMiddleware
{
    public function handle($request, Closure $next)
    {
        $response = $next($request);

        // nejaka akce

        return $response;
    }
}

Zaregistrování middleware

Globální middleware

Pokud chcete, aby se middleware vykonal při každém HTTP požadavku na vaší aplikaci, pak ho jednoduše přidejte do pole $middleware ve třídě app/Http/Kernel.php.

Přidání middleware k routám

Pokud chcete přidat middleware ke specifické routě pak je potřeba přidat middleware do souboru app/Http/Kernel.php. Defaultně proměnná $routeMiddleware v této třídě obsahuje middleware poskytované Laravelem. Při přidání vlastního jednoduše přidejte na jeho konec jeho namespace a libovolný klíč, například:

// trida App\Http\Kernel

protected $routeMiddleware = [
    'auth'       => \Illuminate\Auth\Middleware\Authenticate::class,
    'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
    'bindings'   => \Illuminate\Routing\Middleware\SubstituteBindings::class,
    'can'        => \Illuminate\Auth\Middleware\Authorize::class,
    'guest'      => \App\Http\Middleware\RedirectIfAuthenticated::class,
    'throttle'   => \Illuminate\Routing\Middleware\ThrottleRequests::class,
];

Jakmile je middleware definován v HTTP kernelu, můžete použít metodu middleware pro přidání middleware k routě:

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

K routě můžete přidat i více middleware:

Route::get('/', function () {
    //
})->middleware('first', 'second');

Když přidáváte middleware, můžete také použít celý namespace třídy:

use App\Http\Middleware\CheckAge;

Route::get('admin/profile', function () {
    //
})->middleware(CheckAge::class);

Skupiny middleware

Někdy můžete potřebovat skupinu několika middleware pod jediným klíčem pro jednodušší přidání k routě. To můžete udělat pomocí proměnné $middlewareGroups v HTTP kernelu.

Laravel nabízí vlastní skupiny web a api, které obsahují běžné middleware, které můžete použít pro vaše UI a API cesty:

/**
 * The application's route middleware groups.
 *
 * @var array
 */
protected $middlewareGroups = [
    'web' => [
        \App\Http\Middleware\EncryptCookies::class,
        \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
        \Illuminate\Session\Middleware\StartSession::class,
        \Illuminate\View\Middleware\ShareErrorsFromSession::class,
        \App\Http\Middleware\VerifyCsrfToken::class,
        \Illuminate\Routing\Middleware\SubstituteBindings::class,
    ],

    'api' => [
        'throttle:60,1',
        'auth:api',
    ],
];

Skupiny middleware mohou být přiřazeny k routám a controllerům pomocí stejné syntaxe jako v případě samostatného middleware. Opět, skupiny tak umožňují pohodlně najednou přidat více middleware k routě:

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

Route::group(['middleware' => ['web']], function () {
    //
});

Pro soubor routes/web.php je automaticky aplikována middleware skupina web, definována třídou RouteServiceProvider.

Middleware parametry

Middleware může také obdržet další parametry. Například pokud vaše aplikace potřebuje ověřit, že přihlášený uživatel má přidělenou určitou roli ještě předtím než se vykoná nějaká akce, můžete vytvořit middleware CheckRole, který obdrží název role jako další parametr.

Další parametry pro middleware lze vkládat až po parametru $next:

namespace App\Http\Middleware;

use Closure;

class CheckRole
{
    /**
     * Handle the incoming request.
     *
     * @param  \Illuminate\Http\Request $request
     * @param  \Closure $next
     * @param  string $role
     * @return mixed
     */
    public function handle($request, Closure $next, $role)
    {
        if (!$request->user()->hasRole($role)) {
            // Redirect...
        }

        return $next($request);
    }
}

Middleware parametry mohou být specifikovány při definování routy – název middleware a parametr oddělený dvojtečkou. Více parametrů může být definováno pomocí čárky:

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

Konečný middleware

Někdy je potřeba, aby middleware vykonal nějakou akci až poté, co byla HTTP odpověď odeslána prohlížeči. Například session middleware zapíše session data až po odeslání dat do prohlížeče. Pokud definujete metodu terminate, pak váš middleware bude automaticky zavolán jakmile bude odpověď odeslána:

namespace Illuminate\Session\Middleware;

use Closure;

class StartSession
{
    public function handle($request, Closure $next)
    {
        return $next($request);
    }

    public function terminate($request, $response)
    {
        // uloz session data...
    }
}

Metoda terminate musí obdržet jak požadavek, tak i odpověď. Jakmile je zavolána metoda terminate na váš middleware, Laravel vytvoří novou instanci ze service containeru. Pokud chcete, aby se použila stejná middleware instance když jsou zavolány metody handle a terminate, pak zaregistrujte middleware v service containeru s metodou singleton.