Membuat Halaman Login Kustom yang Aman di Next.js (Part 5)

Dalam dunia Cyber Security, halaman autentikasi (Login) adalah gerbang utama yang menjadi target paling awal dari setiap serangan siber, mulai dari Brute Force hingga pencurian kredensial (Phishing).

Pada jurnal Part 4 sebelumnya, kita telah berhasil memasang "Satpam Virtual" (Middleware) yang menendang akses ilegal. Namun, mengandalkan halaman login bawaan (default) dari NextAuth tidaklah ideal untuk sebuah platform profesional seperti Learning Management System (LMS). Tampilannya yang polos dapat memicu keraguan pengguna, dan secara tidak langsung mengekspos stack teknologi yang kita gunakan.

Melanjutkan fondasi yang telah kita rintis sejak Part 1 (Inisialisasi Database Keamanan), Part 2 (Proteksi API), hingga Part 3 (Keamanan Frontend), jurnal Part 5 ini akan membimbing Anda meracik User Interface (UI) Login kustom yang estetik, namun tetap terhubung secara aman dengan mesin kriptografi NextAuth.

Mengapa Halaman Login Kustom Lebih Aman?

  • Mencegah User Enumeration: Dengan UI kustom, kita memegang kendali penuh atas pesan error. Alih-alih menampilkan "Email tidak terdaftar" (yang memberitahu hacker bahwa email tersebut salah), kita bisa menyamarkannya menjadi pesan generik seperti "Kredensial tidak valid", sehingga peretas tidak bisa menebak-nebak data pengguna.
  • Validasi Pra-Pengiriman (Client-Side Checking): Kita bisa mencegah form terkirim jika format email salah atau password terlalu pendek. Ini akan mengurangi beban server dari serangan spam request.
  • Mitigasi Phishing: Halaman login yang selaras dengan tema aplikasi Anda akan meyakinkan pengguna bahwa mereka berada di domain yang sah, bukan di situs tiruan.

Langkah Praktis: Membangun Antarmuka Login Kustom

1. Membuat Komponen Halaman Login

Buka proyek VS Code Anda. Di dalam folder app, buatlah direktori baru bernama login, lalu buat file page.tsx di dalamnya. (Jalur: app/login/page.tsx).

Karena form ini membutuhkan interaksi pengguna dan pengalihan rute dinamis, kita wajib menggunakan "use client". Copy dan paste kode berikut:

'use client';

import { useState } from 'react';
import { signIn } from 'next-auth/react';
import { useRouter } from 'next/navigation';

export default function LoginPage() {
  const router = useRouter();
  
  // State untuk menyimpan input dan status error
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const [errorMsg, setErrorMsg] = useState('');
  const [isLoading, setIsLoading] = useState(false);

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    setIsLoading(true);
    setErrorMsg(''); // Reset pesan error

    try {
      // Mengirim data ke mesin NextAuth secara aman di latar belakang
      const res = await signIn('credentials', {
        redirect: false,
        email: email,
        password: password,
      });

      if (res?.error) {
        // Taktik Keamanan: Gunakan pesan error generik
        setErrorMsg('Autentikasi gagal. Periksa kembali email dan password Anda.');
        setIsLoading(false);
      } else {
        // Jika sukses, arahkan pengguna ke halaman rute aman (Dashboard/Kelas)
        router.push('/kelas');
        router.refresh();
      }
    } catch (error) {
      setErrorMsg('Terjadi anomali pada sistem jaringan.');
      setIsLoading(false);
    }
  };

  return (
    <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', minHeight: '100vh', backgroundColor: '#edf2f7', fontFamily: 'sans-serif' }}>
      <div style={{ background: '#ffffff', padding: '40px', borderRadius: '8px', boxShadow: '0 4px 6px rgba(0, 0, 0, 0.1)', width: '100%', maxWidth: '400px' }}>
        
        <h2 style={{ textAlign: 'center', color: '#2d3748', marginBottom: '20px' }}>
          Portal Autentikasi
        </h2>

        {/* Tampilan Notifikasi Error */}
        {errorMsg && (
          <div style={{ background: '#fed7d7', color: '#c53030', padding: '10px', borderRadius: '4px', marginBottom: '15px', fontSize: '14px', textAlign: 'center', border: '1px solid #fc8181' }}>
            {errorMsg}
          </div>
        )}

        <form onSubmit={handleSubmit} style={{ display: 'flex', flexDirection: 'column', gap: '15px' }}>
          <div>
            <label style={{ display: 'block', marginBottom: '5px', color: '#4a5568', fontSize: '14px', fontWeight: 'bold' }}>Email Pengguna</label>
            <input 
              type="email" 
              value={email}
              onChange={(e) => setEmail(e.target.value)}
              placeholder="admin@sekolah.com"
              style={{ width: '100%', padding: '10px', borderRadius: '4px', border: '1px solid #cbd5e0', boxSizing: 'border-box' }}
              required
            />
          </div>
          
          <div>
            <label style={{ display: 'block', marginBottom: '5px', color: '#4a5568', fontSize: '14px', fontWeight: 'bold' }}>Kata Sandi</label>
            <input 
              type="password" 
              value={password}
              onChange={(e) => setPassword(e.target.value)}
              placeholder="••••••••"
              style={{ width: '100%', padding: '10px', borderRadius: '4px', border: '1px solid #cbd5e0', boxSizing: 'border-box' }}
              required
            />
          </div>

          <button 
            type="submit" 
            disabled={isLoading}
            style={{ padding: '12px', background: isLoading ? '#a0aec0' : '#2b6cb0', color: 'white', border: 'none', borderRadius: '4px', cursor: isLoading ? 'not-allowed' : 'pointer', fontWeight: 'bold', marginTop: '10px', transition: 'background 0.3s' }}
          >
            {isLoading ? 'Memverifikasi Kredensial...' : 'Masuk ke Sistem'}
          </button>
        </form>

      </div>
    </div>
  );
}

2. Memahami Alur Keamanan Kode (SignIn Function)

Perhatikan fungsi signIn('credentials', { ... }). Ini adalah jembatan penghubung antara form UI kita dengan mesin verifikasi [...nextauth]/route.ts yang kita buat di Part 4.

Dengan menambahkan opsi redirect: false, kita mencegah NextAuth melakukan reload halaman jika login gagal. Hal ini memungkinkan kita menangkap pesan error (res?.error) dan menampilkannya di dalam kotak merah (notifikasi) secara elegan tanpa membuat layar berkedip, mempertahankan pengalaman pengguna (UX) yang sangat responsif.

3. Uji Coba Kunci Gembok

Pastikan server lokal (npm run dev) Anda berjalan. Sekarang, buka URL: http://localhost:3000/login

Cobalah masukkan email dan password yang asal-asalan. Anda akan melihat pesan error generik berwarna merah muncul. Setelah itu, cobalah masukkan email dan password yang benar-benar ada di database MySQL Anda. Secara otomatis, Anda akan diizinkan masuk dan dialihkan kembali ke rute /kelas!

Kesimpulan

Keamanan web (Web Security) tidak hanya bersembunyi di balik baris kode server, melainkan juga terpampang pada antarmuka yang berinteraksi langsung dengan manusia. Dengan merancang UI Login kustom menggunakan next-auth/react, kita berhasil menyeimbangkan antara tingkat keamanan otorisasi yang ketat dan kenyamanan visual bagi para pengguna LMS Anda.

Gembok kini telah terpasang rapi. Pada lembar jurnal berikutnya, kita akan membahas taktik Role-Based Access Control (RBAC)—bagaimana cara membedakan tampilan menu untuk Guru dan Siswa di Next.js. Tetap waspada, dan selamat mengoding!

Berlangganan update artikel terbaru via email:

0 Response to "Membuat Halaman Login Kustom yang Aman di Next.js (Part 5)"

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel