REST API Codeigniter 4 Menggunakan JWT Auth

REST API Codeigniter 4 Menggunakan JWT Auth

Sobatcoding.com - Tutorial Membuat REST API Codeigniter 4 Menggunakan JWT Auth

Kali ini kita kan mencoba membuat REST API menggunakan Codeigniter 4 dan JWT Auth. Berikut langsung saja langkah-langkahnya.

Step 1: Install Codeigniter 4 Via Composer

Langkah pertama kita install terlebih dahulu codeigniter 4 menggunakan composer, jalankan command beriktu di terminal kalian :

composer create-project codeigniter4/appstarter ci4restapi

Step 2: Setup Config dan Database

Setelah proses install selesai kita setup terlebih dahulu config dan koneksi ke database nya.

Copy file env dan paste kemudian rename menjadi .env, lalu ubah beberapa kode di line berikut:

#--------------------------------------------------------------------
# ENVIRONMENT
#--------------------------------------------------------------------

CI_ENVIRONMENT = development

#--------------------------------------------------------------------
# APP
#--------------------------------------------------------------------

app.baseURL = 'http://localhost:8080/'

Setup juga untuk koneksi database di line berikut.

#--------------------------------------------------------------------
# DATABASE
#--------------------------------------------------------------------

database.default.hostname = 'localhost'
database.default.database = 'rest_api'
database.default.username = 'root'
database.default.password = 
database.default.DBDriver = 'MySQLi'

Step 3: Buat Model

Buat sebuah model bernama Users.php di folder App\Models dan masukkan kode berikut.

<?php

namespace App\Models;

use CodeIgniter\Model;

class Users extends Model
{
	protected $DBGroup              = 'default';
	protected $table                = 'm_users';
	protected $primaryKey           = 'id';
	protected $useAutoIncrement     = true;
	protected $insertID             = 0;
	protected $returnType           = 'array';
	protected $useSoftDelete        = false;
	protected $protectFields        = true;
	protected $allowedFields        = ['username', 'password', 'name', 'addrress', 'phone'];

	// Dates
	protected $useTimestamps        = true;
	protected $dateFormat           = 'datetime';
	protected $createdField         = 'created_at';
	protected $updatedField         = 'updated_at';
	protected $deletedField         = 'deleted_at';

	// Validation
	protected $validationRules      = [];
	protected $validationMessages   = [];
	protected $skipValidation       = false;
	protected $cleanValidationRules = true;

	// Callbacks
	protected $allowCallbacks       = true;
	protected $beforeInsert         = [];
	protected $afterInsert          = [];
	protected $beforeUpdate         = [];
	protected $afterUpdate          = [];
	protected $beforeFind           = [];
	protected $afterFind            = [];
	protected $beforeDelete         = [];
	protected $afterDelete          = [];
}

Kalian juga bisa generate file ini secara otomatis mengunakan perintah php spark make:model Users di terminal kalian.

Step 4: Buat Controller

Buatlah sebuah controller bernama UserController.php di folder App\Controllers\Api dan masukkan kode berikut.

<?php

namespace App\Controllers\Api;

use App\Controllers\BaseController;
use App\Models\Users;
use CodeIgniter\API\ResponseTrait;

class UserController extends BaseController
{
	use ResponseTrait;

	public function index()
	{
		$db = new Users;
		$user = $db->get()->getResult();
		return $this->response->setJSON( ['sucess'=> true, 'mesage' => 'OK', 'data' => $user] );
	}

	public function create()
	{
		if( !$this->validate([
			'username' 	=> 'required|is_unique[m_users.username]',
			'password' 	=> 'required|min_length[6]',
			'name'	   	=> 'required',
			'address'	=> 'required',
			'phone'		=> 'required'
		]))
		{
			return $this->response->setJSON(['success' => false, 'data' => null, "message" => \Config\Services::validation()->getErrors()]);
		}

		$insert = [
            'username' => $this->request->getVar('username'),
            'password' => password_hash($this->request->getVar('password'), PASSWORD_DEFAULT),
			'name' => $this->request->getVar('name'),
			'naaddressme' => $this->request->getVar('address'),
			'phone' => $this->request->getVar('phone'),
        ];

		$db = new Users;
		$save  = $db->insert($insert);
		
		return $this->setResponseFormat('json')->respondCreated( ['sucess'=> true, 'mesage' => 'OK'] );
	}

	public function show($id)
	{
		$db = new Users;
		$user = $db->where('id', $id)->first();

		return $this->response->setJSON( ['sucess'=> true, 'mesage' => 'OK', 'data' => $user] );
	}

	public function update($id)
	{
		if (! $this->validate([
            'username' => 'permit_empty|is_unique[m_users.username,id,'.$id.']',
            'password' => 'permit_empty|min_length[6]',
			'name' => 'permit_empty',
			'address' => 'permit_empty',
			'phone' => 'permit_empty',
        ])) {
            return $this->response->setJSON(['success' => false, "message" => \Config\Services::validation()->getErrors()]);
        }

		$db = new Users;
		$exist = $db->where('id', $id)->first();

		if( !$exist )
		{
			return $this->response->setJSON(['success' => false, "message" => 'User not found']);
		}
		
        $update = [
            'username' => $this->request->getVar('username') ? $this->request->getVar('username') : $exist['username'],
            'password' => $this->request->getVar('password') ? password_hash($this->request->getVar('password'), PASSWORD_DEFAULT) : $exist['password'],
			'name' => $this->request->getVar('name') ? $this->request->getVar('name') : $exist['name'],
			'naaddressme' => $this->request->getVar('address')  ? $this->request->getVar('address') : $exist['address'],
			'phone' => $this->request->getVar('phone') ? $this->request->getVar('phone') : $exist['phone']
        ];

        $db = new Users;
        $save  = $db->update( $id, $update);

        return $this->response->setJSON(['success' => true,'message' => 'OK']);
	}

	public function delete($id)
	{
		$db = new Users;
		$db->where('id', $id);
		$db->delete();
		
		return $this->response->setJSON( ['sucess'=> true, 'mesage' => 'OK'] );
	}

}

Kalian juga bisa generate file ini secara otomatis mengunakan perintah php spark make:controller Api\UserController di terminal kalian.

Buat juga controller untuk handle waktu user login, karena saat login inilah waktu kita generate token pertama kali. Buat controller bernama AuthController.php dan masukkan kode berikut.

<?php

namespace App\Controllers;

use App\Controllers\BaseController;
use App\Models\Users;
use App\Libraries\JWTCI4;

class AuthController extends BaseController
{
	public function login()
	{
		if( !$this->validate([
			'username' 	=> 'required',
			'password' 	=> 'required|min_length[6]',
		]))
		{
			return $this->response->setJSON(['success' => false, 'data' => null, "message" => \Config\Services::validation()->getErrors()]);
		}

		$db = new Users;
		$user  = $db->where('username', $this->request->getVar('username'))->first();
		if( $user )
		{
			if( password_verify($this->request->getVar('password'), $user['password']) )
			{
				$jwt = new JWTCI4;
				$token = $jwt->token();

				return $this->response->setJSON( ['token'=> $token ] );
			}
		}else{

			return $this->response->setJSON( ['success'=> false, 'message' => 'User not found' ] )->setStatusCode(409);
		}
		
		
	}
}

 

Step 5: Enable CORS

Buatlah sebuah filter bernama CorsFilter.php dengan command php spark make:filter CorsFilter di terminal kalian. Kemudian masukkan kode berikut di dalam function before.

* @return mixed
	 */
	public function before(RequestInterface $request, $arguments = null)
	{
		header('Access-Control-Allow-Origin: *');
		header("Access-Control-Allow-Methods: GET, POST, OPTIONS, PUT, DELETE");
		header("Access-Control-Allow-Credentials: true");
		header("Access-Control-Max-Age: 86400");
        header("Access-Control-Allow-Headers: X-API-KEY, Origin, X-Requested-With, Content-Type, Accept, Access-Control-Request-Method, Authorization");
        
		
		if ( $request->getMethod() == 'options')
        {
			$response = service('response');
            $response->setJSON(['method' => 'OPTIONS']);
            return $response;
			die();
        }

	}

Langkah selanjutnya adalah register filter tersebut dengan cara buka file App\Config\Filters.php, dan masukkan kode seperti berikut.

/**
	 * Configures aliases for Filter classes to
	 * make reading things nicer and simpler.
	 *
	 * @var array
	 */
	public $aliases = [
		'csrf'     => CSRF::class,
		'toolbar'  => DebugToolbar::class,
		'honeypot' => Honeypot::class,
	
		'cors' 	   => \App\Filters\CorsFilter::class, //register cors
	];

Kita register dengan nama cors didalam variable $alias.

Step 6: Install PHP JWT untuk Codeigniter 4

Kita install terlebih dahulu package JWT dengan command seperti berikut.

composer require firebase/php-jwt

Kemudian kita buat sebuah library baru bernama JWTCI4, dan masukkan kode berikut.

<?php

namespace App\Libraries;

use Firebase\JWT\JWT;
use Firebase\JWT\Key;

class JWTCI4 {

    private $key;

    private $iss;

    private $ttl; //in minutes

    private $iat;

    private $exp;

    private $nbf;

    private $jti;

    public function __construct()
    {
        $this->setConfig()->setExpiredDate();
    }

    protected function setConfig()
    {
        $this->key = getenv("jwt.secretkey");
        $this->ttl = getenv("jwt.ttl") ? getenv("jwt.ttl") : 60;
        $this->iss = $this->getCurrentURL();
        $this->jti = $this->setTime( date("Y-m-d H:i:s"));

        return $this;
    }

    protected function setExpiredDate()
    {
        $now = date("Y-m-d H:i:s");
        $this->iat = $this->setTime( $now );
        $this->nbf = $this->setTime( $now );
        $this->exp = $this->setTime( date("Y-m-d H:i:s", strtotime("+".$this->ttl." MINUTES")) );
        return $this;
    }

    public function token()
    {
        $payload = [
            'iss' => $this->iss,
            'iat' => $this->iat,
            'exp' => $this->exp,
            'nbf' => $this->nbf,
            'jti' => $this->jti
        ];

        return JWT::encode($payload, $this->key, 'HS256');
    }

    public function parse($token)
    {
    
        $bearerToken = $this->getBearerToken( $token );
        if( !$bearerToken ) return ['success' => false, 'message' => 'Token Invalid'];

        try {
            $decoded = JWT::decode($bearerToken, new Key($this->key, 'HS256') );

            return ['success' => true];
        }catch (\Exception $e){

            return ['success' => false, 'message' => $e->getMessage()];
        }
        
    }

    public function getBearerToken($token)
    {
        $token = explode(" ", $token);
        if( !isset($token[0]) && $token[0] != 'Bearer' )
        {
            return false;
        }

        return $token[2];
    }

    public function setTime($date)
    {
        return strtotime($date);
    }

    public function getCurrentURL()
    {
        $url = ( isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? 'https://' : 'http://') . $_SERVER['HTTP_HOST']. $_SERVER['REQUEST_URI'];

        return $url;
    }
    
}

 

Kita buka kembali file .env dan tambahkan beberapa variable berikut.

#JWT
jwt.secretkey= 'eyJhbGciOiJIUzI1NiJ9.eyJSb2xlIjoiQWRtaW4iLCJJc3N1ZXIiOiJJc3N1ZXIiLCJVc2VybmFtZSI6IkphdmFJblVzZSIsImV4cCI6MTY1MTAyOTU5MSwiaWF0IjoxNjUxMDI5NTkxfQ.GEqEGG2K-AQwjGEwDRzChXRIQVm5GtJPbTfcXHrgX5w'
jwt.ttl = 1440

Ada dua varibale yaitu secret key dan ttl. Secret key nantinya akan digunakan sebgai key saat generate token JWT, sedangkan ttl digunakan untuk setting expired date token tersebut. Untuk format time nya kita pakai menit. Contoh diatas yang kita pakai adalah 1440 menit atau 24 jam.

Selanjutnya kita buat midleware untuk authentifikasi bahwa API harus diakses menggunakan token JWT. Caranya kita buat sebuah file Filter bernama AuthFilter.php, dan masukkan kode seperti berikut.

use App\Libraries\JWTCI4;

      ...
	/**
	 * @param RequestInterface $request
	 * @param array|null       $arguments
	 *
	 * @return mixed
	 */
	public function before(RequestInterface $request, $arguments = null)
	{

		if( !$request->getHeader('Authorization') )
		{
			$response = service('response');
            $response->setJSON(['success' => false, 'message' => 'Unauthorized. Token is required!']);
            $response->setStatusCode(401);
            return $response;
		}

		//validasi JWT
		$token = $request->getHeader('Authorization');
		$jwt = new JWTCI4;
		$verifiy = $jwt->parse($token);
		if( !$verifiy['success'] )
		{
			$response = service('response');
            $response->setJSON($verifiy);
            $response->setStatusCode(401);
            return $response;
		}

	}

	...

Jangan lupa untuk di register terlebih dahulu.

/**
	 * Configures aliases for Filter classes to
	 * make reading things nicer and simpler.
	 *
	 * @var array
	 */
	public $aliases = [
		'csrf'     => CSRF::class,
		'toolbar'  => DebugToolbar::class,
		'honeypot' => Honeypot::class,
		'cors' 	   => \App\Filters\CorsFilter::class,
		'auth' 	   => \App\Filters\AuthFilter::class, //register auth
	];

Fungsi filter tersebut adalah untuk security agar tidak semua bisa mengakses API tersebut secara bebas.

Step 7: Buat Route

Tambahkan beberapa route baru di file App\Config\Routes.php seperti berikut .

/*
 * --------------------------------------------------------------------
 * Route Definitions
 * --------------------------------------------------------------------
 */

// We get a performance increase by specifying the default
// route since we don't have to scan directories.

$routes->group('api', ["filter" => "cors", "auth"],  function($routes) {
	$routes->get('users', 'Api\UserController::index');
	$routes->post('users', 'Api\UserController::create');
	$routes->get('users/(:num)', 'Api\UserController::show/$1');
	$routes->patch('users/(:num)', 'Api\UserController::update/$1');
	$routes->delete('users/(:num)', 'Api\UserController::delete/$1');
});

$routes->post('api/users/token', 'Api\AuthController::login', ['filter' => 'cors']);

Step 8: Jalankan API

Berikut hasil REST API kita test menggunakan Postman.

 

Demikan tutorial kali ini. Semoga bermanfaat.

Untuk full sourcode bisa kalian lihat diaccount github sobatcoding di link berikut https://github.com/sobatcoding21/CI4RestApi.git.