Langsung ke konten utama

Project Website CMS: Membuat Fitur Login Admin

Tanpa berlama-lama. Yuk, langsung kita mulai mengerjakan fitur login pada project yang dibuat menggunakan Vue 3 sebagai frontend dan Laravel 10 sebagai backend.

Lakukan instalasi project

Kalau belum tahu caranya melakukan instalasi, silahkan simak postingan ini:

  • Install Laravel: Coming soon

Struktur project

Dalam case ini, folder frontend dan backend berada pada folder yang sama. Ini adalah struktur project yang saya buat (opsional):


🔵 Backend: Laravel 10 (folder backend/)

backend/ ├── app/ │ └── Http/ │ ├── Controllers/ │ │ └── Api/ │ │ └── AuthController.php ← Controller login │ └── Middleware/ │ └── VerifyCsrfToken.php ← Bypass CSRF untuk /api/login ├── config/ │ ├── cors.php ← Atur CORS │ └── session.php ← Atur same_site=lax ├── routes/ │ └── api.php ← Route untuk /api/login ├── .env ← Konfigurasi Sanctum + Session

🟠 Frontend: Vue 3 (folder frontend/)

frontend/ ├── src/ │ ├── api/ │ │ └── index.js ← Axios instance setup │ ├── stores/ │ │ └── auth.js ← Pinia Auth Store │ ├── views/ │ │ └── admin/ │ │ └── Login.vue ← Halaman Login Admin │ ├── router/ │ │ └── index.js ← Routing frontend │ ├── layouts/ │ │ └── AdminLayout.vue ← Layout admin setelah login ├── package.json

Daftar Library yang Harus Diinstall (dengan Penjelasan)

🔵 Backend: Laravel 10

Saat memulai Laravel backend, kita membutuhkan library tambahan:

Laravel Sanctum

Kegunaan:

  • Untuk API token authentication yang simple, ringan, aman.

  • Mengelola login/logout token di API berbasis SPA seperti Vue 3.

Cara install:

composer require laravel/sanctum
php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"

🟠 Frontend: Vue 3 (Vite)

Saat setup Vue 3 frontend, kita butuh beberapa library:

Axios

Kegunaan:

  • Untuk melakukan HTTP request dari frontend ke backend API.

Cara install:

npm install axios

Vue Router

Kegunaan:

  • Untuk mengelola navigasi halaman SPA (Single Page Application).

Cara install:

npm install vue-router@4

Pinia

Kegunaan:

  • Untuk State Management, seperti login status (token, user) yang digunakan di banyak halaman.

Cara install:

npm install pinia

Tailwind CSS (opsional)

Kegunaan:

  • Untuk mempercepat styling halaman tanpa bikin CSS manual dari awal.
  • Misal: form login, tombol, layout admin.

Cara install:

npm install -D tailwindcss@3.4.1 postcss autoprefixer
npx tailwindcss init -p

Recap Instalasi yang Harus Dilakukan

Platform Library Command
Backend Laravel Sanctum
  • composer require laravel/sanctum
  • php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"
Frontend Axios npm install axios
Frontend Pinia npm install pinia
Frontend Vue Router npm install vue-router@4
Frontend Tailwind CSS (styling)
  • npm install -D tailwindcss@3.4.1 postcss autoprefixer
  • npx tailwindcss init -p
Frontend (Optional) Heroicons npm install @heroicons/vue

Penulisan Baris Kode

A. Backend (Laravel 10)

1. Membuat AuthController untuk Login

directory: backend/app/Http/Controllers/Api/AuthController.php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use App\Models\User;

class AuthController extends Controller
{
    public function login(Request $request)
    {
        $user = User::where('email', $request->email)->first();

        if (! $user) {
            return response()->json(['message' => 'Email tidak ditemukan'], 404);
        }

        if (!Hash::check($request->password, $user->password)) {
            return response()->json(['message' => 'Password salah'], 403);
        }

        $token = $user->createToken('api-token')->plainTextToken;

        return response()->json([
            'message' => 'Login berhasil',
            'user'    => $user,
            'token'   => $token,
        ]);
    }
}

2. Membuat route API login

directory: backend/routes/api.php

use App\Http\Controllers\Api\AuthController;

Route::post('/login', [AuthController::class, 'login']);

3. Bypass CSRF untuk route /api/login

directory: backend/app/Http/Middleware/VerifyCsrfToken.php

protected $except = [
    'api/login',
];

4. Update .env

directory: backend/.env

SANCTUM_STATEFUL_DOMAINS=localhost:5173
SESSION_DOMAIN=localhost
APP_URL=http://localhost:8000

5. Update config/cors.php

directory: backend/config/cors.php

'paths' => [
    'api/*',
    'sanctum/csrf-cookie',
],

'allowed_origins' => [
    'http://localhost:5173',
],

'allowed_headers' => ['*'],
'allowed_methods' => ['*'],
'supports_credentials' => true,

6. Update config/session.php

directory: backend/config/session.php

'same_site' => 'lax',

B. Frontend (Vue 3)

1. Buat Axios instance dengan withCredentials

directory: frontend/src/api/index.js

import axios from 'axios';

const api = axios.create({
  baseURL: "http://localhost:8000",
  withCredentials: true,
  headers: {
    Accept: "application/json",
    "Content-Type": "application/json",
  },
});

api.interceptors.request.use((config) => {
  const token = localStorage.getItem('token');
  if (token) {
    config.headers.Authorization = `Bearer ${token}`;
  }
  return config;
}, (error) => {
  return Promise.reject(error);
});

export default api;

2. Buat Pinia Store untuk Auth

directory: frontend/src/stores/auth.js

import { defineStore } from 'pinia';
import api from '@/api';

export const useAuthStore = defineStore('auth', {
  state: () => ({
    user: null,
    token: localStorage.getItem('token') || '',
  }),
  getters: {
    isAuthenticated: (state) => !!state.token,
  },
  actions: {
    async login(credentials) {
      try {
        await api.get('/sanctum/csrf-cookie');
        const response = await api.post('/api/login', credentials);

        this.token = response.data.token;
        this.user = response.data.user;

        localStorage.setItem('token', this.token);
        localStorage.setItem('user', JSON.stringify(this.user));

        api.defaults.headers.common['Authorization'] = `Bearer ${this.token}`;
        return true;
      } catch (error) {
        throw error.response?.data?.message || 'Login failed';
      }
    },
    logout() {
      this.token = '';
      this.user = null;
      localStorage.removeItem('token');
      localStorage.removeItem('user');
      delete api.defaults.headers.common['Authorization'];
    },
  },
});

3. Membuat Form Login

directory: frontend/src/views/admin/Login.vue

<template>
  <div class="flex items-center justify-center bg-gray-100 min-h-screen">
    <div class="w-full max-w-md bg-white p-8 rounded-xl shadow-lg">
      <h1 class="text-2xl font-semibold text-center mb-6">Login as Admin</h1>

      <form @submit.prevent="handleLogin">
        <div class="mb-4">
          <label class="block text-gray-700 mb-1">Email</label>
          <input type="email" v-model="form.email" class="..." placeholder="Enter your email" />
        </div>

        <div class="mb-6">
          <label class="block text-gray-700 mb-1">Password</label>
          <input type="password" v-model="form.password" class="..." placeholder="Enter your password" />
        </div>

        <div class="text-sm text-red-600 mb-4">
          <span v-if="errorMessage">{{ errorMessage }}</span>
        </div>

        <button type="submit" class="..." :disabled="isLoading">
          <template v-if="isLoading">
            <svg class="animate-spin ..." ...></svg>
            Loading...
          </template>
          <template v-else>
            Login
          </template>
        </button>
      </form>
    </div>
  </div>
</template>

<script setup>
import { ref } from 'vue';
import { useRouter } from 'vue-router';
import { useAuthStore } from '@/stores/auth';

const auth = useAuthStore();
const router = useRouter();

const form = ref({
  email: '',
  password: '',
});
const errorMessage = ref('');
const isLoading = ref(false);

const handleLogin = async () => {
  isLoading.value = true;
  errorMessage.value = '';

  try {
    const success = await auth.login(form.value);
    if (success) {
      router.push('/admin/dashboard');
    }
  } catch (error) {
    errorMessage.value = error;
  } finally {
    isLoading.value = false;
  }
};
</script>

4. Setup Router dan Protected Admin

directory: frontend/src/router/index.js

import { createRouter, createWebHistory } from 'vue-router';
import { useAuthStore } from '@/stores/auth';
import PublicLayout from '@/layouts/PublicLayout.vue';
import AdminLayout from '@/layouts/AdminLayout.vue';
import Home from '@/views/public/Home.vue';
import About from '@/views/public/About.vue';
import Dashboard from '@/views/admin/Dashboard.vue';
import Login from '@/views/admin/Login.vue';

const routes = [
  {
    path: '/',
    component: PublicLayout,
    children: [
      { path: '', component: Home },
      { path: 'about', component: About },
    ],
  },
  {
    path: '/admin/login',
    name: 'admin-login',
    component: Login,
  },
  {
    path: '/admin',
    component: AdminLayout,
    children: [
      { path: 'dashboard', name: 'admin-dashboard', component: Dashboard },
    ],
    meta: { requiresAuth: true },
  },
];

const router = createRouter({
  history: createWebHistory(),
  routes,
});

router.beforeEach((to, from, next) => {
  const auth = useAuthStore();
  if (to.meta.requiresAuth && !auth.isAuthenticated) {
    next({ name: 'admin-login' });
  } else if (to.name === 'admin-login' && auth.isAuthenticated) {
    next({ name: 'admin-dashboard' });
  } else {
    next();
  }
});

export default router;

Yuk, langsung cobain yuk!
Semoga berhasil

Komentar

Postingan populer dari blog ini

Instalasi Vue 3 menggunakan Vue CLI & Vite

Instalasi Vue 3 menggunakan Vue CLI Vue CLI adalah alat untuk membuat proyek Vue secara otomatis dengan konfigurasi yang sudah diatur sebelumnya. Ini adalah pilihan yang bagus jika kamu ingin memiliki kontrol lebih atas pengaturan proyek dan konfigurasi build. Langkah-langkah: Install Vue CLI secara global (jika belum terpasang) : Buka terminal dan jalankan perintah berikut untuk menginstal Vue CLI secara global di komputer kamu: npm install -g @vue/cli Buat proyek baru menggunakan Vue CLI : Setelah Vue CLI terpasang, kamu bisa membuat proyek Vue 3 baru dengan perintah berikut: // Pilih salah satu vue create nama-proyek npm create vue@latest nama-proyek // Rekomendasi karena sesuai Official Docs Gantilah nama-proyek dengan nama yang kamu inginkan untuk proyekmu. Pilih konfigurasi : Ketika perintah di atas dijalankan, Vue CLI akan menanyakan beberapa pilihan konfigurasi. Pilihlah opsi yang sesuai (misalnya, memilih preset default yang sudah menyertakan Babe...

Membuat code block/ syntax highlighter pada Blogger

Untuk membuat code block (blok kode) di Blogger, Anda dapat menggunakan tag HTML <pre><code> ... </code></pre> . Dengan ini, Anda dapat menampilkan kode dengan format yang sesuai dan mencegah interpretasi tag HTML di dalamnya. Langkah-langkah membuat code block/ syntax highlighter: Buka editor postingan Blogger Masuk ke Blogger, lalu pilih postingan yang ingin Anda edit atau buat postingan baru Beralih ke mode HTML Di editor postingan, klik tombol "HTML" (biasanya di sebelah kiri) untuk beralih ke tampilan HTML Tambahkan tag <pre><code>...</code></pre> Posisikan kursor di tempat di mana Anda ingin menampilkan blok kode. Kemudian, ketik atau tempelkan kode Anda di antara tag <pre><code> dan </pre> . Contoh: <pre><code> console.log("Hello, world!"); </code></pre> Sembunyikan tag <p> Jika Anda menambahkan blok kode di dalam paragraf, hilangkan tag <p...

Mengatasi Error: Module Apache pada XAMPP Control Panel tidak dapat digunakan

Module Apache XAMPP tidak bisa di Start?  Apakah kamu sedang mengalami kendala module Apache di XAMPP control panel tidak bisa digunakan? Mungkin saja, yang sedang kamu alami saat ini, sama dengan yang pernah saya alami. Gambar 1: Pesan error module Apache di XAMPP Control Panel Bila pesan error yang kamu dapatkan ketika klik Start module Apache sama seperti gambar diatas, penyebabnya adalah port yang digunakan oleh module Apache XAMPP telah digunakan oleh layanan / aplikasi lain di komputer kamu. Ya, mungkin hal seperti ini yang disebut dengan konflik port. Cari tahu penyebab konflik port Pertama-tama, cari tahu layanan / aplikasi apa yang sedang menggunakan port yang sama dengan yang digunakan oleh module Apache XAMPP. Untuk itu, buka command prompt (cmd), lalu ketikkan perintah dibawah ini: netstat -ano | find "80" Bagaimana mengatasinya? Setelah mengetahui penyebab konflik port tersebut, apa yang harus dilakukan untuk mengatasi masalah tersebut? Ada 2 cara untuk mengatasi...