Mengatur Middleware PHP Router Miladrahimi

26 November 2024
Bagikan:
Mengatur Middleware PHP Router Miladrahimi

Dalam kesempatan kali ini saya akan menjelaskan tentang bagaimana mengatur router pada salah satu library php router yang dibuat oleh milad rahimi seorang programmer berkebangsaan Iran. Saya tidak akan terlalu menjelaskan Panjang lebar mengenai metode pengrutean aplikasi menggunakan php router miladrahimi, sebab kamu bisa membacanya sendiri pada laman github miladrahimi/phprouter.

Librari PHP Router dari miladrahimi sendiri tidaklah menyediakan handle ‘middleware’ secara langsung, sehingga kamu perlu membuatnya sendiri terlebih dahulu. Jadi disini kita akan membuat dua buah middleware yang akan kita tambahkan dalam router group dari library php routernya. middleware pertama untuk mengecek user terautentifikasi atau tidak sedangkan middleware yang kedua adalah untuk mengecek hak akses dari user yang terautentifikasi

AuthMiddleware.php

<?php
namespace Auth;
use Psr\Http\Message\ServerRequestInterface;
use Laminas\Diactoros\Response\JsonResponse;
class AuthMiddleware
{
    /**
     * Middleware handler
     *
     * @param ServerRequestInterface $request
     * @param callable $next
     * @return mixed
     */
    public function handle(ServerRequestInterface $request, callable $next)
    {
        if (session_status() === PHP_SESSION_NONE) {
            session_start();
        }
      
       	
        if (!$this->isAuthenticated($request)) {
		    //$this->logUnauthorizedAccess($request);
		    return new JsonResponse(
		        ['error' => 'Unauthorized', 'message' => 'Anda harus login untuk mengakses halaman ini.'],
		        401
		    );
		}
        return $next($request);
    }
    private function isAuthenticated(ServerRequestInterface $request): bool
	{
	    // Misalnya cek apakah user ada di sesi
	    if (isset($_SESSION['user'])) {
	        return true;
	    }
	    // Tambahkan cek lain jika perlu, seperti token atau cookie
	    // return $this->validateToken($request);
	    return false;
	}
	private function logUnauthorizedAccess(ServerRequestInterface $request): void
	{
	    $logMessage = sprintf(
	        "[%s] Unauthorized access attempt from IP: %s\n",
	        date('Y-m-d H:i:s'),
	        $request->getServerParams()['REMOTE_ADDR'] ?? 'unknown'
	    );
	    file_put_contents(__DIR__ . '/../logs/auth.log', $logMessage, FILE_APPEND);
	}
}

RoleMiddleware.php

<?php
namespace Auth;
use Psr\Http\Message\ServerRequestInterface;
use Laminas\Diactoros\Response\JsonResponse;
class RoleMiddleware
{
    /**
     * Peran yang diizinkan
     *
     * @var array
     */
    private array $allowedRoles;
    /**
     * Constructor untuk RoleMiddleware
     *
     * @param array|string $roles
     */
    public function __construct(array|string $roles)
    {
        $this->allowedRoles = (array)$roles; // Ubah string menjadi array jika diperlukan
    }
    /**
     * Middleware handler
     *
     * @param ServerRequestInterface $request
     * @param callable $next
     * @return mixed
     */
    private function logForbiddenAccess(ServerRequestInterface $request): void
    {
        $logMessage = sprintf(
            "[%s] Forbidden access attempt from IP: %s. User role: %s\n",
            date('Y-m-d H:i:s'),
            $request->getServerParams()['REMOTE_ADDR'] ?? 'unknown',
            $_SESSION['user']['role']
        );
        file_put_contents(__DIR__ . '/../logs/role.log', $logMessage, FILE_APPEND);
    }
    public function handle(ServerRequestInterface $request, callable $next)
    {
        if (!$this->isAuthenticated()) {
            return new JsonResponse(
                ['error' => 'Unauthorized', 'message' => 'Anda harus login untuk mengakses halaman ini.'],
                401
            );
        }
        if (!$this->hasRequiredRole()) {
            //$this->logForbiddenAccess($request); // Log jika akses ditolak berdasarkan peran
            return new JsonResponse(
                ['error' => 'Forbidden', 'message' => 'Anda tidak memiliki akses ke halaman ini.'],
                403
            );
        }
        return $next($request);
    }
     /**
     * Memeriksa apakah pengguna terautentikasi
     *
     * @return bool
     */
    private function isAuthenticated(): bool
    {
        return isset($_SESSION['user']);
    }
    /**
     * Memeriksa apakah pengguna memiliki peran yang sesuai
     *
     * @return bool
     */
    private function hasRequiredRole(): bool
    {
        return in_array($_SESSION['user']['role'], $this->allowedRoles, true);
    }
}

Setelah middleware dibuat kita hanya perlu mengaksesnya dalam router group dengan bentuk array. Dibawah ini merupakan beberapa variasi atau contoh penggunaan middleware dalam routernya :

<?php 
use MiladRahimi\PhpRouter\Router;
use Auth\AuthMiddleware;
use Auth\RoleMiddleware;
$router = Router::create();
// Grup rute untuk admin dengan middleware autentikasi dan otorisasi
$router->group(['middleware' => [new AuthMiddleware(), new RoleMiddleware('administrator')]], function (Router $router) {
    $router->get('/admin/dashboard', [AdminController::class, 'dashboard']);
    $router->get('/admin/settings', [AdminController::class, 'settings']);
});
//only AuthMiddleware
$router->group(['middleware' => new AuthMiddleware()], function (Router $router) {
    $router->get('/user/profile', [UserController::class, 'profile']);
    $router->post('/user/settings', [UserController::class, 'updateSettings']);
});
//another
$router->group(['middleware' => new AuthMiddleware()], function (Router $router) {
    // Hanya pengguna dengan peran tertentu yang dapat mengakses ini
    $router->group(['middleware' => new RoleMiddleware(['administrator', 'editor'])], function (Router $router) {
        $router->get('/posts/manage', [PostController::class, 'managePosts']);
        $router->post('/posts/create', [PostController::class, 'createPost']);
    });
});
//another
$router->group(['middleware' => new AuthMiddleware()], function (Router $router) {
    // Rute untuk admin
    $router->group(['middleware' => new RoleMiddleware('administrator')], function (Router $router) {
        $router->get('/admin/dashboard', [AdminController::class, 'dashboard']);
        $router->get('/admin/settings', [AdminController::class, 'settings']);
    });
    // Rute untuk editor
    $router->group(['middleware' => new RoleMiddleware('editor')], function (Router $router) {
        $router->get('/editor/posts', [EditorController::class, 'viewPosts']);
        $router->post('/editor/posts/update', [EditorController::class, 'updatePost']);
    });
    // Rute umum untuk semua pengguna yang login
    $router->get('/user/profile', [UserController::class, 'profile']);
});

Memisah - Misah Router

Selanjutnya dimisalkan router yang kita bangun itu tidak disatukan kedalam satu file melainkan dipisah - pisah menjadi beberapa dengan tujuan untuk membuat kode terlihat lebih rafi serta untuk mengelompokan kode tersebut berdasarkan fungsi atau hak aksesnya, misal jika kode tersebut dibangun untuk admin maka kita buat router file khusus admin atau router untuk user biasa maka ada router khusus untuk user biasa.

Dimisalkan kita tahu routernya secara terpisah didalam folder lain yang berbeda. Dimisalkan bahwa kamu punya struktur direktori seperti berikut :
 

/config
    routes.php          <-- File utama untuk memanggil semua rute
/routes
    admin.php           <-- File untuk rute admin
    user.php            <-- File untuk rute pengguna
    public.php          <-- File untuk rute publik (tanpa autentikasi)

/routes/admin.php

use MiladRahimi\PhpRouter\Router;
use Auth\AuthMiddleware;
use Auth\RoleMiddleware;

return function (Router $router) {
    $router->group(['middleware' => [new AuthMiddleware(), new RoleMiddleware('administrator')]], function (Router $router) {
        $router->get('/admin/dashboard', [AdminController::class, 'dashboard']);
        $router->post('/admin/settings', [AdminController::class, 'updateSettings']);
    });
};

/routes/user.php


use MiladRahimi\PhpRouter\Router;
use Auth\AuthMiddleware;

return function (Router $router) {
    $router->group(['middleware' => new AuthMiddleware()], function (Router $router) {
        $router->get('/user/profile', [UserController::class, 'profile']);
        $router->post('/user/settings', [UserController::class, 'updateSettings']);
    });
};

/routes/public.php

use MiladRahimi\PhpRouter\Router;

return function (Router $router) {
    $router->get('/home', [PublicController::class, 'home']);
    $router->get('/about', [PublicController::class, 'about']);
    $router->post('/contact', [PublicController::class, 'contact']);
};

Selanjutnya panggil semua file tersebut melalui satu file router utama /config/routes.php

use MiladRahimi\PhpRouter\Router;
// Inisialisasi router
$router = Router::create();
// Tambahkan view jika diperlukan
$router->setupView(__DIR__ . '/../views');
// Load semua file rute
foreach (glob(__DIR__ . '/../routes/*.php') as $routeFile) {
    $routeDefinition = require $routeFile;
    if (is_callable($routeDefinition)) {
        $routeDefinition($router);
    }
}

$router->dispatch();

Middleware Global

Kita juga bisa menggunakan metode lain dalam looping pada saat memanggil file - file router yang terpisahnya. Contoh misalnya kita ingin mengatur middleware secara global untuk semua rute, maka kamu bisa memodifikasi file /config/routes.php menjadi seperti berikut :

$router->group(['middleware' => new AuthMiddleware()], function (Router $router) {
    // Load semua file rute
    foreach (glob(__DIR__ . '/../routes/*.php') as $routeFile) {
        $routeDefinition = require $routeFile;
        if (is_callable($routeDefinition)) {
            $routeDefinition($router);
        }
    }
});

File diatas bisa saja kita tambah fungsi lain untuk mengecek atau validasi pemanggilan file :

foreach (glob(__DIR__ . '/../routes/*.php') as $routeFile) {
    $routeDefinition = require $routeFile;
    if (!is_callable($routeDefinition)) {
        error_log("Invalid route definition in file: {$routeFile}");
        continue;
    }
    $routeDefinition($router);
}

Dalam konteks kode global middleware diatas, tentu setiap halaman yang berada pada rute akan dicek autentifikasinya, apakah user memiliki hak akses atau tidak

Catatan :

Middleware perlu diakses dalam bentuk array didalam router group 

['middleware' => [new AuthMiddleware()]]

Jika kita butuh middleware tambahan maka cukup tambahkan nilainya kedalam array

['middleware' => [new AuthMiddleware(), new RoleMiddleware(['admin'])]]

 

Mengatur Middleware PHP Router Miladrahimi | Blog Pursem.com | Pursem