Memahami Middleware dalam Laravel

Middleware Laravel adalah penengah antara request yang masuk dengan controller yang dituju yang berpengaruh pada request dan respons. Misalnya kita ingin memverifikasi setiap request yang masuk seperti melakukan pengecekan status login, privillage, CSRF (Cross-Site Request Forgery) atau yang lainnya.


Pemanggilan Middleware

Cara menggunakan atau memanggil middleware, berikut contoh-contohnya:

Individual Route

Memanggil middleware dalam individual route

Route::get('admin', [
    'uses' => 'MyController@index',
    'middleware' => 'new-middleware'
]);

Route Groups

Memanggil middleware dalam route groups

Route::group(['middleware' => 'new-middleware'], function () {
    Route::get('/', function ()    {
        // Uses new-middleware Middleware
    });

    Route::get('admin/profile', function () {
        // Uses new-middleware Middleware
    });
});

Controller

Memanggil middleware dalam controller. Jika ingin berlaku pada semua method dalam controller:

class MyController extends Controller
{
    function __construct()
    {
        $this->middleware('new-middleware');
    }
    ...
}

Jika hanya ingin pada method tertentu saja kita bisa menggunakan only dan except.

class MyController extends Controller
{
    function __construct()
    {
        $this->middleware('new-middleware', ['only' => ['foo', 'bar']]); //selected method
        $this->middleware('other-middleware', ['except' => ['baz']]) ; //exclude method
    }
}

Membuat Middleware

Untuk membuat middleware baru kita dapat membuat file class baru dalam direktori /app/Http/Middleware/ misal dengan isi seperti ini

namespace App\Http\Middleware;

use Closure;

class NewMiddleware
{
    public function handle($request, Closure $next)
    {
        // Letakkan kode disini...
    }
}

Middleware memiliki method khusus bernama handle() yang memiliki dua parameter yaitu $request dan Closure $next. Kita lihat contoh sederhana dibawah ini

public function handle($request, Closure $next)
{
    $user = Auth::user();
    if($user->role === User::ROLE_ADMIN) {
        return $next($request);
    }

    return redirect('home');
}

Method handle() diatas memfilter setiap request yang masuk harus berupa User dengan role sebagai ROLE_ADMIN. Jika request yang masuk adalah User::ROLE_ADMIN maka request akan diteruskan kepada controller dengan memanggil method $next($request). Tapi apabila bukan User::ROLE_ADMIN maka akan di redirect ke home.

Parameter Middleware

Middleware juga bisa menerima parameter tambahan, seperti contoh dibawah ini, misal untuk memverifikasi bahwa $request->user() harus memiliki $role tertentu.

namespace App\Http\Middleware;

use Closure;

class RoleMiddleware
{
    public function handle($request, Closure $next, $role)
    {
        if (! $request->user()->hasRole($role)) {
            // Redirect...
        }

        return $next($request);
    }
}

Parameter middleware dapat dispesifikan ketika pemanggilannya dalam route yaitu dengan memisahkan antara nama middleware dan parameter menggunakan :, contoh:

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

Before dan After Middleware

Middleware dalam Laravel dibagi menjadi dua macam; After Middleware dan Before Middleware.

Before Middleware adalah Middleware yang diproses sebelum request masuk kedalam Controller dan After Middleware adalah Middleware yang diproses setelah request masuk kedalam Controller.

Bagaimana mendefinisikannya, kita lihat perbedaan kode berikut:

Before Middleware

namespace App\Http\Middleware;

use Closure;

class BeforeMiddleware
{
    public function handle($request, Closure $next)
    {
        // Hadang request yang masuk

        return $next($request)
    }
}

Contoh penggunaannya

public function handle($request, Closure $next)
{
    $user = Auth::user();
    if($user->role === User::ROLE_ADMIN) {
        return $next($request);
    }

    return redirect('home');
}

Jika bukan ROLE_ADMIN maka tidak boleh mengaksesnya dan dikembalikan ke home.

After Middleware

namespace App\Http\Middleware;

use Closure;

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

        // Lakukan sesuatu terhadap response yang diperoleh

        return $response
    }
}

Contoh penggunaannya

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

    // menyimpan IP dan path yang telah diakses ke database
    DB::table('access_logs')->insert([
    	'path' => $request->path(),
        'ip' => $request->getClientIp(),
        'created_at' => new DateTime,
        'updated_at' => new DateTime
    ]);

    return $response
}

Meregistrasikan Middleware

Middleware belum bisa digunakan sebelum diregistrasikan terlebih dahulu dengan cara-cara sebagai berikut:

Secara Global

Meregistrasikan secara global berarti middleware akan selalu dipanggil pada setiap request yang masuk, caranya ialah dengan menambahkan kode kedalam array $middleware di app/Http/Kernel.php. Pahami kode dibawah ini

protected $middleware = [
    ...
    \App\Http\Middleware\NewMiddleware::class, //New middleware
];

Pada Routes

Memasang middleware pada route tertentu bisa juga dilakukan dengan terlebih dahulu meregistrasikannya kedalam array $routeMiddleware di app/Http/Kernel.php.

protected $routeMiddleware = [
    ...
    'new-middlware' => \App\Http\Middleware\NewMiddleware::class, //New middleware
];

Dengan Mengelompokkan (Middleware Groups)

Bagaimana jika satu route membutuhkan banyak middleware? kan repot memanggil banyak middleware sekaligus. Solusinya ialah diregistrasikan menggunakan Middleware Groups. Menggunakan Middleware Groups kita bisa mengelompokkan beberapa middleware menjadi satu sehingga memudahkan dalam penggunaanya sebagaimana individual middleware. Kita buka app/Http/Kernel.php lihat pada array $middlewareGroups

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,
    ],

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

Berdasarkan kode diatas, secara default Laravel memiliki dua buah middleware group yaitu web dan api.

Middleware group web didalamnya mengandung beberapa middleware sekaligus yaitu EncryptCookiesAddQueuedCookiesToResponseStartSessionShareErrorsFromSession dan VerifyCsrfToken sehingga kita tidak usah repot-repot memanggil middleware tersebut satu persatu tetapi cukup dengan menggunakan key dari middleware group yaitu web.

Key dari middleware group seperti web dan api bisa kita panggil baik pada individual routeroute groups maupun controller.

Perlu dicatat, bahwa middleware group web oleh Laravel otomatis telah diterapkan pada route sebagai middleware default.

Terminable Middleware

Adakalanya kita tetap butuh sebuah aksi ketika response telah diberikan kepada User, baik menggunakan Before Middleware maupun After Middleware.

Terminable middleware menggunakan method bernama terminate() dan akan tetap dieksekusi meskipun terdapat Before Midleware yang gagal. Misalnya untuk pencatatan log seperti contoh sederhana dibawah ini

public function handle($request, Closure $next)
{
    $user = Auth::user();
    if($user->role === User::ROLE_ADMIN) {
        return $next($request);
    }

    return redirect('home');
}

public function terminate($request, $response)
{
    //Tulis kode untuk aksi pencatatan log disini
}

Method terminate() akan tetap dieksekusi meskipun User bukan ROLE_ADMIN

Comments