Proteksi Autentikasi Route dengan Navigation Guards Vue Router

wahyunanangwidodo

wahyunanangwidodo Kamis, 03 Juni 2021

Proteksi Autentikasi Route dengan Navigation Guards Vue Router

Dengan Navigation Guards yang ada di vue router, kita bisa melindungi atau menjaga route yang kita miliki apakah harus melewati autentikasi atau dengan syarat tertentu untuk dapat membukanya atau menuju ke suatu halaman.

Proteksi Autentikasi Route dengan Navigation Guards Vue Router

Untuk contoh dan cara penggunaannya, mari kita membuatnya.

Instalasi Laravel, Membuat Database dan Tabel

Kita siapkan projek terlebih dahulu. Kita mulai dari instalasi laravel, membuat database dan tabel.

laravel new lavue-app

Silahkan buat database MySQL baru dan hubungkan dengan aplikasi.

//.env 
DB_DATABASE=lavue_app
DB_USERNAME=root
DB_PASSWORD=

Kemudian jalankan perintah migrasi.

php artisan migrate
MariaDB [lavue_app]> show tables;
+-------------------------+
| Tables_in_newlavueroles |
+-------------------------+
| failed_jobs             |
| migrations              |
| password_resets         |
| users                   |
+-------------------------+

Konfigurasi Vue dan Vue Router

Kita lanjutkan untuk proses instalasi vue, mengatur vue instance dan membuat route dengan vue router.

npm install
npm install vue vue-loader vue-template-compiler --save-dev
npm install vue-router

Buka resources > app.js, buat seperti dibawah ini.

require('./bootstrap');

import Vue from 'vue';

import VueRouter from 'vue-router'

Vue.use(VueRouter)

import App from './components/App.vue'
import Home from './components/Home.vue'  
import Dashboard from './components/Dashboard.vue' 

const router = new VueRouter({
  mode: 'history',
  routes: [
      {
          path: '/',
          name: 'home',
          component: Home
      }, 
      {
        path: '/dashboard',
        name: 'dashboard',
        component: Dashboard, 
      }
  ],
})
 
 
new Vue({
  el: '#app',
  components: { App },
  router,
});

Silahkan buat folder baru di direktori js dengan nama components dan tambahkan didalamnya file App.vue, Home.vue, dan Dashboard.vue.

//App.vue
<template>
  <div>
     <router-link :to="{name: 'home'}" >Home</router-link> 
     <router-link :to="{name: 'dashboard'}">Dashboard</router-link> 
     
    <div class="container">
	 <router-view></router-view>
    </div>
  
  </div>
</template>
//Home.vue
<template>
  <div>
    Home
  </div>
</template>
//Dashboard.vue
<template>
  <div>
    Dashboard
  </div>
</template>

Selanjutnya buka file welcome.blade.php, ubah html yang ada dengan dibawah ini.

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="csrf-token" content="{{csrf_token()}}">
    <title>Lavue</title> 
    <style>body{padding:2rem}.container{margin-top:2rem}</style>
  </head>
  <body>
    <div id="app">
      <app></app>
    </div>
    <script src="{{ mix('js/app.js') }}"></script>
  </body>
</html>

Ubah route di web.php dengan dibawah ini.

Route::get('/{any}', function(){
    return view('welcome');
})->where('any', '.*');

Terakhir buka file webpack.mix.js, tambahkan .vue() seperti dibawah ini untuk memeriksa dan menginstall depedensi atau plugin babel secara otomatis jika ada yang diperlukan.

mix.js('resources/js/app.js', 'public/js').vue();

Kemudian lakukan compiling.

npm run dev

Setelah selesai mari kita jalankan aplikasi pada browser.

php artisan serve
Proteksi Autentikasi Route dengan Navigation Guards Vue Router

Vue Router sudah terinstal dan siap digunakan.

Penggunaan Navigation Guards

Sekarang mari kita coba menggunakan navigation guards. Kita akan menggunakan router.beforeEach untuk guard asinkron, dan setiap guard memiliki parameter seperti dibawah ini untuk menerima argument.

router.beforeEach((to, from, next) => {
  // ...
})
  • to : Untuk memilih target objek route atau properti dari objek route.
  • from : Untuk memilih objek route route yang sedang aktif.
  • next : Perintah selanjutnya untuk tugas yang harus diselesaikan.

Objek route bisa dilihat pada gambar di atas atau lihat sendiri dengan vue devtools.

Kita coba buat fungsi pengalihan yang sederhana dulu untuk mencobanya. Silahkan tambahkan dibawah ini pada file app.js, letakan diatas vue instance.

...

router.beforeEach((to, from, next) => {
  if (to.name !== 'home') next({ name: 'home' })
  else next()
})

...

Kembali kita compile. Gunakan npm run watch untuk compiling setiap ada perubahan file js, dan jalankan php artisan serve di tab baru.

Silahkan coba buka http://localhost:8000/dashboard. Selain route 'home' kita tidak bisa mengaksesnya.

Login User

Contoh penggunaan lainnya untuk sistem login pengguna. Mari kita buat metode login user dan menggunakan token JWT.

Kita tambahkan user terlebih dahulu menggunakan seeder.

php artisan make:seeder UserSeeder

Buka file UserSeeder.php dan buat buat seperti dibawah ini.

<?php

namespace Database\Seeders;

use Illuminate\Database\Seeder;
use App\Models\User;

class UserSeeder extends Seeder
{
    public function run()
    {
        $user = new User;
        $user->name = "user";
        $user->email = "user@mail.com";
        $user->password = bcrypt('12345678'); 
        $user->save();
    }
}

Lalu tambahkan class seeder di file DatabaseSeeder.php di dalam run() method seperti dibawah ini.

public function run()
{
  $this->call([ UserSeeder::class ]);
}

Kemudian lakukan seeding.

php artisan db:seed

Kita akan login dengan email user@mail.com dan password 12345678.

Instalasi JWT

Kita lanjutnya untuk instalasi dan konfigurasi JWT. Jalankan pertinah dibawah ini secara berututan.

composer require tymon/jwt-auth:dev-develop --prefer-source

php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider"

php artisan jwt:secret

Kemudian buka model User.php dan tambahkan implements JWTSubject, getJWTIdentifier(), dan getJWTCustomClaims() seperti dibawah ini.

<?php

namespace App\Models;

use Tymon\JWTAuth\Contracts\JWTSubject;
...

class User extends Authenticatable implements JWTSubject
{
    use HasFactory, Notifiable;

    ...

    public function getJWTIdentifier()
    {
        return $this->getKey();
    }
 
    public function getJWTCustomClaims()
    {
        return [];
    }
}

Metode Login

Selanjutnya kita buat sebuah controller baru.

php artisan make:controller UserController

Buka UserController.php, buat seperti dibawah ini.

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use JWTAuth;

class UserController extends Controller
{
    public function login(Request $request)
    {   
        $credentials = $request->only('email', 'password');

        if (auth()->attempt($credentials)) { 
            $response = [
                'user' => auth()->user(),
                'token' => JWTAuth::fromUser(auth()->user())
            ]; 
        } 
        
        return response()->json($response);
    }
}

Lalu tambahkan route dibawah ini pada api.php.

Route::post('login', [\App\Http\Controllers\UserController::class, 'login']);

Login Component

Silahkan buat component Login.vue, kemudian import dan tambahkan route link.

//Login.vue
<template>
  <div>
    <form @submit.prevent="loginForm">
      <input type="email" v-model="email" placeholder="email" required>
      <input type="password" v-model="password" placeholder="password" required>
      <button type="submit">Login</button>
    </form>
  </div>
</template>

<script>
  export default { 
    
      data(){
          return {
              email: "",
              password: "",
          }
      },
      methods : {
          loginForm() { 
             axios.post('api/login', {
                email: this.email,
                password: this.password
             })
             .then(response => {
                    
              	localStorage.setItem('user',JSON.stringify(response.data.user))
                localStorage.setItem('token',response.data.token)
                     
                this.$router.push('dashboard')
                      
              })
              .catch(error => { 
              	console.error(error);
             });
          }
      }
  }
</script>

Kita lihat metode loginForm() di atas. Ketika kita berhasil login, kita simpan respon berupa token dan objek user ke local storage browser untuk kita akses dikemudian.

Selanjutnya silahkan import component Login.vue di app.js dan tambahkan juga link navigasi.

//app.js
import Login from './components/Login.vue' 

{
   path: '/login',
   name: 'login',
   component: Login, 
}

//App.vue
<router-link :to="{name: 'login'}">Login</router-link>

Setelah itu kembali ke app.js, ubah guard yang ada dengan dibawah ini.

router.beforeEach((to, from, next) => {
  let token = localStorage.getItem('token') != null;
  if (to.name === 'login' && token){
    next({ name: 'home' })
  }else if(to.matched.some(record => record.meta.requiresAuth)) {
      if (!token) {
        next({
          path: '/login',
          query: { redirect: to.fullPath }
        })
      } else { 
         next() 
    }
  }else {
     next()
  }
})

Jadi data token yang kita simpan pada local storage tadi kita akses pada guard yang akan menunda route untuk dilakukan pengecekan apakah token tersedia atau tidak.

Lalu meta requiresAuth (kita bisa buat dengan nama apa saja) yang ditambahkan adalah untuk menjaga akses route atau url.

Pada route dashboard tambahkan properti meta seperti di bawah ini.

{
   path: '/dashboard',
   name: 'dashboard',
   component: Dashboard, 
   meta: {
      requiresAuth: true, 
   }
},

Terakhir, buka component Dashboard.vue dan buat seperti dibawah ini. Kita ambil objek user dari local storage untuk ditampilkan pada dom.

<template>
  <div>
   <p>name: {{user.name}}</p> 
   <p>email: {{user.email}} </p> 
  </div>
</template>

<script>
    export default {
      data(){
          return {
            user : JSON.parse(localStorage.getItem('user')) 
          }
      } 
    }
</script>

Sekarang tinggal mencobanya. Silahkan buka route / url yang ada dengan login atau tanpa login.

Logout

Untuk logout, kita tinggal kosongkan local storage dengan membuat metode seperti dibawah ini.

//App.vue
<template>
  <div>
     <router-link :to="{name: 'home'}" >Home</router-link> 
     <router-link :to="{name: 'dashboard'}">Dashboard</router-link> 
     <router-link :to="{name: 'login'}" v-if="!loggedIn">Login</router-link> 
     <a v-if="loggedIn" @click="logout">Logout</a> 
    <div class="container">
      <router-view  @setToken="userToken"></router-view>
    </div>

  </div>
</template>

<script>
    export default {
      data(){
          return { 
            loggedIn  : false
          }
      }, 
        mounted() {
         this.userToken() 
      },
        methods : {  
          userToken() {
            this.loggedIn = localStorage.getItem('token') != null 
        },
        logout(){
            localStorage.removeItem('token')
            localStorage.removeItem('user')
            this.userToken() 

            this.$router.push('/')
        }
      }
    }
</script>

Buka Login.vue, tambahkan emit seperti dibawah ini untuk transfer data setalah login agar reaktif.

.then(response => {
  
  this.$emit('setToken')
  
})

Selesai. Kita sampai disini. Silahkan dicoba, dikembangkan, dan lakukan eksperimen.

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel

Berlangganan

Berlangganan untuk mendapat pemberitahuan artikel terbaru via email.