Tutorial API Development dan Authorization dengan Laravel 5.7

30 November 2018 08:56:33

Tutorial API Development dan Authorization dengan Laravel 5.7

Laravel sebagai salah satu framework PHP paling diminati, selain digunakan untuk web development juga sangat mudah digunakan untuk API Development lho.. Di tutorial kali ini saya akan membagikan step by step apa saja yang perlu kita lakukan untuk membuat API Service di Laravel. 

 

1. INSTALLATION

Pertama-tama kita install laravel dulu dengan command "composer create-project laravel/laravel latihan_api"

Siapkan database kosong, setup koneksi ke database kosong di file .env. Sekarang kita akan menyiapkan tabel-tabel yang ceritanya adalah isi API kita nantinya. 

 

 

2. PREPARATION

a. Membuat Migrations

Masuk ke folder "database/migrations", hapus file xxxx_create_password_ resets_table.php karena kita nggak membutuhkan file itu utk latihan ini..

Setelah itu kita buat 1 file migrations untuk menyimpan data access token. Manajemen Token adalah salah satu model autentikasi API paling dasar yang wajib digunakan. Sebenarnya teknik autentikasi API ada cukup banyak, tapi kita coba yang dasar ini dulu saja ya.. Jalankan command : "php artisan make:migration token_management" untuk membuat migration baru. Isinya adalah struktur seperti ini : 

...
    public function up()
    {
        //
        Schema::create('token_management', function(Blueprint $tb){
            $tb->increments('id');
            $tb->integer('user_id'); //related to table users
            $tb->string('access_token');
            $tb->datetime('expired_at');
            $tb->tinyinteger('is_active')->nullable();
            $tb->timestamps();
        });
    }

    public function down()
    {
        //
        Schema::drop('token_management');
    }

...

 

Untuk data dummy lainnya juga kita bebas membuat migration baru lainnya.. Misalnya seperti ini : "php artisan make:migration post". Isi migrationnya seperti ini : 

...
    public function up()
    {
        Schema::create('post', function(Blueprint $tb){
            $tb->increments('id');
            $tb->string('title');
            $tb->text('content');
            $tb->timestamps();
        });
    }

    public function down()
    {
        //
        Schema::drop('post');
    }
...

 

Jika semua file migrate sudah disiapkan, sekarang jalankan command "php artisan migrate" untuk otomatis membuat struktur database yang bersangkutan. Setelah struktur database sukses dibuat, sekarang kita tinggal menyiapkan dummy data dengan seeder.. 

 

b. Membuat Seeder

Sekarang buka "database/seeds/DatabaseSeeder.php", dan buat data dummy dengan bantuan facade DB (boleh diganti sesuka hati) seperti contoh dibawah ini.

<?php

use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;

class DatabaseSeeder extends Seeder
{
    public function run()
    {
    	//create default user
    	DB::table('users')->insert([
    		'name' => 'Christian Rosandhy',
    		'email' => 'tianrosandhy@gmail.com',
    		'password' => bcrypt('123456'), //Hash default laravel
    		'created_at' => date('Y-m-d H:i:s'),
    		'updated_at' => date('Y-m-d H:i:s'),
    	]);

    	//create example dummy post
    	DB::table('post')->insert([
    		'title' => 'Post Example Title',
    		'content' => 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ut, dignissimos magnam eum voluptate saepe quis iste. Dolor aliquid, et beatae.',
    		'created_at' => date('Y-m-d H:i:s'),
    		'updated_at' => date('Y-m-d H:i:s'),
    	]);
    	DB::table('post')->insert([
    		'title' => 'Another Title',
    		'content' => 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Nihil, odit ab ea labore distinctio aut quam commodi deserunt expedita repudiandae nostrum. Illo aliquid, nemo quos maiores eos nostrum accusamus odit.',
    		'created_at' => date('Y-m-d H:i:s'),
    		'updated_at' => date('Y-m-d H:i:s'),
    	]);

    }
}

 

Seeder ini berguna supaya kita bisa mengisi data default atau data dummy pada tabel yang sudah dibuat tadi. Bisa sih kita langsung mengisinya di database, akan tetapi jauh lebih rapi jika kita membuatnya via seeder seperti ini.

Usahakan isi kolom seeder yang dibuat sesuai dengan struktur yang sudah ditentukan di migrate sebelumnya ya, tabel "token_management" ga perlu dibuatkan seedernya, karena itu nanti kita mainkan di authentication, dan sifatnya dinamis tergenerate sendiri.

 

c. Membuat Model

Ini step preparation terakhir.. Semua file tabel migration yang sudah kita buat tadi sekarang perlu dibuatkan model sebagai perwakilan instance. jalankan command-command ini : 

php artisan make:model Models/TokenManagement
php artisan make:model Models/Post

Isi modelnya kita cuma perlu mendefinisikan nama tabelnya aja biar aman..

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class TokenManagement extends Model
{
    public $table = 'token_management';
}

 

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    //
    public $table = 'post';
}

 

Preparation selesai! Sekarang ke tahap implementasinya ya..

 

 

3. IMPLEMENTATION

Dalam tahap implementasi ini, kita membutuhkan aplikasi API Testing, yang paling umum digunakan adalah Postman. Kalau belum punya bisa download dulu di https://www.getpostman.com/apps karena kita akan sangat membutuhkan software ini untuk testing.

 

a. API Token Generation by Username + Password

Pertama-tama kita buat controller bernama ApiController dengan command "php artisan make:controller ApiController"

Di controller ApiController tersebut kita bisa buatkan method bernama generateToken() untuk menampung request pembuatan token. Setelah itu kita buka route di "routes/api.php", hapus semua isinya dan daftarkan route baru berikut ini: 

<?php
Route::post('generate-token', 'ApiController@generateToken');

Logika isi controller ApiController method generateToken() adalah seperti ini : 

- validasi request email & password dengan facade Validator;
- jika input sudah oke, cek apakah email & password tsb valid;
- jika valid, generate token, simpan ke tabel token_management;
- return response yang berisi token yang baru dibuat;

Dengan logika tsb, isi controller ApiController kira-kira jadi seperti ini : 

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Validator;
use App\User;
use App\Models\TokenManagement;

class ApiController extends Controller
{

    public function generateToken(Request $request){
    	//expect request : email + password.
    	//if fail will return json response
    	$validate = Validator::make($request->all(), [
    		'email' => 'required|email',
    		'password' => 'required|string'
    	]);
    	if($validate->fails()){
    		//kalau ada salah input, tampilkan error dalam format json
    		return [
    			'error' => $validate->errors(),
    			'data' => false
    		];
    	}

    	//cek email
    	$cek_user = User::where('email', $request->email)->first();
    	if(empty($cek_user)){
    		return [
    			'error' => 'Email not found',
    			'data' => false
    		];
    	}

    	//cek password
    	if(!password_verify($request->password, $cek_user->password)){
    		return [
    			'error' => 'Invalid password provided',
    			'data' => false
    		];
    	}

    	//setelah melewati semua filter diatas, artinya email dan password sudah benar. 
    	$token_instance = $this->registerToken($cek_user);
    	return [
    		'error' => false,
    		'data' => $token_instance
    	];
    }

    protected function registerToken(User $user){
    	//generate custom hash sebagai auth token
    	$generated_token = base64_encode(sha1(rand(1, 10000) . uniqid() . time()));
    	//manage token ini akan expired dalam jangka waktu berapa lama
    	$expired = date('Y-m-d H:i:s', strtotime('+1 day'));

    	//proses simpan token ke database
    	$token_instance = new TokenManagement;
    	$token_instance->user_id = $user->id;
    	$token_instance->access_token = $generated_token;
    	$token_instance->expired_at = $expired;
    	$token_instance->is_active = 1;
    	$token_instance->save();

    	//setelah token direcord ke database, kembalikan nilai token ke response
    	return $token_instance;
    }

}

Sekarang kita tes API Request Token ini menggunakan Postman. Set URL ke "localhost/latihan_api/public/ api/generate-token" (kalau dijalankan menggunakan artisan serve, URLnya adalah localhost:8000/api/generate-token). Set methodnya ke POST, dan isi Paramsnya dengan key : username, value : email yang terdaftar di database user, dan key : password, value : password yang terdaftar di database user. Jika sukses hasil responsenya adalah seperti ini : 

API Token Request

Dengan contoh hasil response tersebut, maka access token yang boleh digunakan untuk request API lainnya adalah "YmZjMjI... bla bla bla". Untuk itu sekarang kita perlu membuat middleware yang memvalidasi token yang nantinya akan diinput user di seluruh request API (kecuali API request token ini)

 

b. Middleware untuk Validasi access_token.

Jalankan command : "php artisan make:middleware CheckToken", setelah itu buka middleware yang sudah kita buat di "app/Http/Middleware/ CheckToken.php". Logic yang dibutuhkan dalam middleware ini kira-kira seperti ini : 

- Get access_token via Header Authorization. (dalam latihan ini kita pakai header Authorization : Bearer)
- Cek apakah access_token yang didapatkan itu ada di database token_management atau tidak. Jika tidak munculkan error forbidden
- Jika ada, lakukan pengecekan apakah token tersebut sudah expired atau belum. Jika sudah expired munculkan pesan error token expired.
- Jika seluruh kondisi diatas sudah dipenuhi, lanjutkan request.

Dengan logic tersebut, kira-kira isi middleware CheckToken adalah seperti ini : 

<?php

namespace App\Http\Middleware;

use Closure;
use App\Models\TokenManagement;

class CheckToken
{

    public function handle($request, Closure $next)
    {
        //get token via header
        $token = $request->header('Authorization');
        if(empty($token)){
            return response()->json([
                'error' => 'Authorization Header is empty'
            ]);
        }

        //format bearer token : 
        //Bearer[spasi]randomhashtoken 
        $pecah_token = explode(" ", $token);
        if(count($pecah_token) <> 2){
            return response()->json([
                'error' => 'Invalid Authorization format'
            ]);
        }

        if(trim($pecah_token[0]) <> 'Bearer'){
            return response()->json([
                'error' => 'Authorization header must be a Bearer'
            ]);
        }


        $access_token = trim($pecah_token[1]);

        //cek apakah access_token ini ada di database atau tidak
        $cek = TokenManagement::where('access_token', $access_token)->first();
        if(empty($cek)){
            return response()->json([
                'error' => 'Forbidden : Invalid access token'
            ]);
        }

        //cek apakah access_token expired atau tidak
        if(strtotime($cek->expired_at) < time() || $cek->is_active != 1){
            return response()->json([
                'error' => 'Forbidden : Token is already expired. '
            ]);
        }

        //jika semua kondisi dipenuhi, lanjutkan request
        return $next($request);
    }
}

Setelah middleware tersebut disimpan, sekarang kita perlu mendaftarkan middleware ini ke kernel yang terletak di "app/Http/Kernel.php". Pada bagian $routeMiddleware, tambahkan list array baru : 

$routeMiddleware = [
    ...
    'check-token' => \App\Http\Middleware\CheckToken::class,
];

 

c. Testing Middleware dengan membuat API Endpoint Baru

Ini langkah implementasi terakhir untuk latihan API kita saat ini.. Sekarang kita buat controller baru yang ceritanya untuk mengakses data post dengan command : "php artisan make:controller PostController". Secara fungsi, API PostController ini nantinya hanya akan menampilkan list post yang tersedia. Isi PostController kira-kira cukup seperti ini saja : 

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\Post;

class PostController extends Controller
{

    public function index(){
        return [
            'error' => false,
            'data' => Post::all()
        ];
    }

    public function detail($id){
        $post = Post::find($id);
        if(empty($post)){
            return [
                'error' => 'Post data not found'
            ];
        }

        return [
            'error' => false,
            'data' => $post
        ];
    }
}

Cara menampilkan API Responsenya sederhana bukan? Iya, hanya dengan return format array atau object akan otomatis diterjemahkan dalam format JSON oleh Laravel. Sekarang apabila API Endpoint ini hanya boleh diakses dengan access_token, artinya route yang mengarah ke controller ini harus diarahkan ke middleware terlebih dahulu. Dengan demikian, isi "routes/api.php" sekarang kita tambahkan seperti ini (yang di baris sebelumnya dibiarkan) : 

...
//semua route API yang membutuhkan authentication sekarang didaftarkan dalam grup middleware sesuai dengan nama yang sudah dibuat di kernel
Route::group(['middleware' => 'check-token'], function(){
    Route::get('post', 'PostController@index');
    Route::get('post/{id}', 'PostController@detail');
    //kalau nanti ada endpoint yang butuh authentication tinggal dimasukkan di grup ini saja
}); 

Jika sudah selesai sekarang kita tes sekalian middleware dan Post API Endpointnya. Endpoint yang akan kita tes adalah "localhost/latihan_api/ public/api/post" dengan method GET. Percobaan pertama adalah dengan mengakses endpoint ini tanpa header Authorization, hasilnya adalah seperti ini : 

API Response tanpa Header Authorization

Untuk testing Authorization Bearer Token, masuk ke tab "Authorization" di Postman, kemudian typenya diubah ke "Bearer Token". Masukkan access_token hasil dari API Request Token sebelumnya disana. Apabila access_token tersebut valid, maka data endpoint post tersebut muncul sesuai dengan yang sudah dibuat di PostController.

Header Authorization Success

Tapi apabila access_token yang kita berikan di header Authorization Bearer Token tersebut sudah expired, maka request endpoint yang sama akan memberi response seperti ini : 

Expired Token Response

 

 

4. LATIHAN

Sudah selesai!

Inti dari tutorial kali ini banyak berbicara di sekitar teknik Authorization. Memang masih jauh dari sempurna, karena itu sebagai bahan latihan, mungkin kalian bisa coba-coba dengan pengembangan lebih lanjut berikut ini : 

a. Membuat API Endpoint baru dengan teknik yang sama seperti post endpoint di contoh. Misalnya menampilkan data produk.

b. Membuat API Endpoint untuk merevoke / auto expired access_point (cluenya : mengubah field "is_active" di tabel token_management dari 1 menjadi 0 )

c. Membuat function helper ataupun class tambahan untuk memformat JSON output menjadi lebih konsisten. Contoh format konsisten : 

{
    "type" : "error",
    "message" : "Invalid input",
    "error" : {
        "email" : ["The email field is required"],
        "password" : ["The password field is required"]
    },
    "data" : false
},

{
    "type" : "success",
    "message" : "",
    "error" : false,
    "data" : {
        "id" : 1,
        "title" : "Example Title",
        "description" : "lorem ipsum dolor sit amet"
    }
}

d. Membuat token generate dengan JWT (JSON Web Token). Kalau yang tadi itu generatenya hanya via hash sederhana, sekarang bisa dicoba latihan menggunakan JWT, konsepnya nggak terlalu berbeda tapi implementasinya perlu sedikit berhati-hati..

 

Selamat mencoba.. Untuk mendownload langsung file project jadinya klik https://tianrosandhy.com/download/prompt/latihan-api-zip. Jika ada kesulitan, atau masalah bisa langsung diskusi via komentar dibawah ini..

0
3
SHARE

Contact Me