Vue · Bab 8
Login, Token, dan Guard
Alur login berbasis token dari kredensial sampai header Authorization Bearer, store sesi di Pinia, interceptor request dan respons, guard rute dengan meta, peran dan 403, pesan 429, serta untung-rugi tempat menyimpan token.
Aplikasi Vue di tingkat 5 berbicara dengan API yang sebagian endpoint-nya hanya boleh dipakai orang yang sudah masuk. Bab ini menyambungkan semua yang sudah kamu pelajari: store Pinia (bab 7) menyimpan sesi, interceptor axios (bab 5) menempelkan token ke setiap request, dan router (bab 6) menjaga halaman yang butuh login. Contohnya: anggota Perpustakaan Pelita masuk untuk memperpanjang pinjaman.
8.1 Alur Token
API Laravel tingkat 4 memakai token sederhana. Alurnya:
1. Form login → POST /api/login { email, password }
2. Server ← 200 { token: "…" } (salah: 401, terlalu sering: 429)
3. Klien → simpan token di store (memori)
4. Setiap request → header Authorization: Bearer <token>
5. Server ← 200 data | 401 token tidak berlaku | 403 peran tidak cukup
Token adalah string buram: bagi klien, ia hanya deretan karakter yang dikirim balik apa adanya. Jangan mengurainya, jangan memotongnya, dan jangan menebak isinya (misalnya membaca nama atau peran dari potongan token). Nama dan peran diambil dari endpoint profil, bukan dari token.
Ada dua arti 401 yang harus dibedakan:
| Dari mana | Artinya | Yang dilakukan klien |
|---|---|---|
| request login | email atau password salah | tampilkan pesan di form, tetap di halaman masuk |
| request lain | token tidak berlaku lagi (sesi habis, dicabut) | lupakan token, arahkan ke halaman masuk |
8.2 Store Sesi
Sesi dipakai banyak komponen (menu, halaman, guard), jadi tempatnya store. Contoh ini memakai fungsi tiruan lokal masukTiruan sebagai pengganti server login, karena di bab ini yang dipelajari adalah alurnya.
🧪 Coba ubah: ketik password rahasia, lalu Keluar. Perhatikan bahwa “keluar” di klien hanya melupakan token di memori.
Belum ada output.
8.3 Interceptor Request: Header Bearer
Menulis header di setiap pemanggilan api.get(...) mudah terlupa. Interceptor request dijalankan axios sebelum setiap request instance itu, jadi header cukup ditulis sekali. Contoh ini memakai adapter lokal yang hanya mencetak header yang akan dikirim ke konsol, tanpa server.
🧪 Coba ubah: hapus if (sesi.token !== ''). Request tanpa token sekarang membawa Bearer kosong, yang bagi server sama dengan tidak membawa token, tetapi mengotori log dan membingungkan saat mencari galat.
Belum ada output.
Interceptor membaca store saat request dibuat, bukan saat interceptor dipasang. Karena itu ia memanggil useSesi() di dalam fungsinya.
8.4 Guard Rute dengan meta
Halaman yang butuh login ditandai di definisi rute dengan meta: { perluLogin: true }. Lalu satu router.beforeEach memeriksa setiap perpindahan. Di Vue Router 5 guard mengembalikan keputusan: objek rute berarti “alihkan ke sini”, tidak mengembalikan apa-apa berarti “lanjut”. Parameter next dari versi lama tidak dipakai lagi.
🧪 Coba ubah: tambahkan rute /profil dengan meta: { perluLogin: true } dan tautannya di menu. Guard yang sama langsung menjaganya tanpa kode tambahan.
Belum ada output.
query: { kembali: … } menyimpan tujuan semula, sehingga setelah login pengguna kembali ke halaman yang tadi ia minta, bukan ke beranda.
8.5 Interceptor Respons: 401 Sesi
Token bisa berhenti berlaku kapan saja: dicabut admin, kedaluwarsa, atau pengguna keluar dari perangkat lain. Interceptor respons menangkap 401 dari request mana pun di satu tempat:
api.interceptors.response.use(
(res) => res,
(galat) => {
const status = galat.response ? galat.response.status : 0;
const dariLogin = galat.config.url === '/login';
if (status === 401 && !dariLogin) {
useSesi().lupakan();
router.replace({ name: 'masuk' });
}
return Promise.reject(galat); // pemanggil tetap menerima galatnya
},
);
Pengecualian dariLogin penting. Tanpanya, password yang salah ketik (401 dari /login) dianggap sesi habis: token dilupakan dan pengguna dialihkan ulang ke halaman masuk, sehingga ?kembali hilang dan pesan “Email atau password salah.” tidak sempat terbaca.
8.6 Peran dan 403
Setelah login, endpoint profil memberi tahu peran pengguna, misalnya anggota atau pustakawan. Tombol yang hanya berguna untuk satu peran disembunyikan:
<button v-if="sesi.peran === 'pustakawan'" type="button" @click="hapusBuku(b)">Hapus buku</button>
Menyembunyikan tombol adalah soal kenyamanan, bukan keamanan. Anggota yang mengirim request hapus lewat konsol tetap ditolak server dengan 403 (sudah masuk, tetapi tidak berhak). Bedakan pesannya: 401 “silakan masuk lagi”, 403 “kamu tidak punya izin untuk aksi ini”.
8.7 Terlalu Banyak Percobaan: 429
Endpoint login dibatasi, misalnya lima percobaan per menit. Percobaan berikutnya dijawab 429. Tampilkan pesan umum: “Terlalu banyak percobaan, coba lagi sebentar lagi.” Header Retry-After memang dikirim server, tetapi browser tidak mengizinkan JavaScript membacanya dari origin lain kecuali server membukanya lewat CORS, jadi jangan menjanjikan hitungan mundur yang tepat.
8.8 Di Mana Token Disimpan?
| Tempat | Bertahan setelah muat ulang | Risiko utama |
|---|---|---|
| memori (store Pinia) | tidak: harus login ulang | paling kecil; hilang saat tab ditutup |
localStorage | ya | skrip jahat hasil XSS bisa membacanya dan mengirimnya ke luar |
cookie httpOnly | ya | tidak terbaca JavaScript; butuh pengaturan server (sesi Sanctum stateful, CSRF) |
Lab dan contoh di kursus ini menyimpan token di memori. Di dalam sandbox lab, localStorage bahkan melempar SecurityError. Ingat juga: “keluar” di klien hanya melupakan token; token baru benar-benar mati bila server mencabutnya (Laravel bab 15). Bab 10 membahas pilihan ini lagi untuk aplikasi produksi.
Rangkuman
- Login: kredensial → token buram → store → header
Authorization: Bearer <token>lewat interceptor request. - 401 dari login = kredensial salah; 401 dari request lain = sesi habis → lupakan token, ke halaman masuk.
router.beforeEach+meta.perluLoginmenjaga tampilan; server tetap penjaga sebenarnya (401, 403).- 429 dijawab dengan pesan umum; token di memori adalah pilihan paling aman untuk mulai.
Berikutnya: Lab bab 8 membangun login kasir Smart Retail lengkap: store, pesan 401 dan 429, header Bearer, guard, dan keluar otomatis.