Tutorial Laravel & ReactJS #11: Keamanan dan Validasi (Client & Server)

Tutorial #11: Menyempurnakan Keamanan dan Validasi (Client & Server)

Halo penjaga gerbang aplikasi! Hari ini kita akan mengunci pintu dan jendela aplikasi kita dari data nakal dan pengguna iseng. Kita akan bahas validasi di sisi klien (React) dan server (Laravel), proteksi rute, serta penanganan error yang ramah. Siap jadi satpam digital? 

😂 Joke keamanan: "Kenapa aplikasi bank perlu validasi? Soalnya kalau nggak, yang nabung bisa jadi alien!" 👽

Yang akan kita lakukan:

  • ✅ Validasi input di React (client-side) biar user tidak salah isi form.
  • ✅ Menampilkan pesan error dari server (Laravel) dengan SweetAlert.
  • ✅ Memperkuat proteksi rute (private route) dan middleware role.
  • ✅ Menangani error jaringan dan server error (500) dengan baik.
  • ✅ Membersihkan data input sebelum dikirim ke server.

Bagian 1: Validasi di Sisi Client (React)

Validasi di React penting supaya pengguna tidak mengirim data kosong atau salah format. Ini seperti satpam di pintu masuk yang menanyakan "KTP-nya mana?" sebelum masuk.

Contoh: Form login dan ubah password. Kita akan perbaiki form login dengan validasi sederhana.

Validasi sederhana di LoginPage:

const validateForm = () => {
  if (!email) {
    Swal.fire('Email kosong', 'Email harus diisi', 'warning');
    return false;
  }
  if (!email.includes('@')) {
    Swal.fire('Email tidak valid', 'Gunakan format email yang benar', 'warning');
    return false;
  }
  if (!password) {
    Swal.fire('Password kosong', 'Password harus diisi', 'warning');
    return false;
  }
  if (password.length < 6) {
    Swal.fire('Password terlalu pendek', 'Minimal 6 karakter', 'warning');
    return false;
  }
  return true;
};

const handleSubmit = async (e) => {
  e.preventDefault();
  if (!validateForm()) return;
  // lanjut ke API...
};

Dengan ini, pengguna langsung tahu kalau ada yang salah tanpa harus nunggu respon server.

💡 Tips: Untuk validasi yang lebih kompleks, kamu bisa pakai library seperti Formik + Yup. Tapi untuk tutorial ini, manual sudah cukup.

Bagian 2: Validasi di Sisi Server (Laravel)

Validasi client bisa dilewati oleh hacker (misal dengan disable JavaScript). Maka kita harus punya validasi di server sebagai benteng terakhir. Di Laravel, kita sudah melakukannya di controller dengan method validate atau Validator.

Contoh di method login (AuthController):

$request->validate([
    'email' => 'required|email',
    'password' => 'required',
]);

Jika validasi gagal, Laravel otomatis mengembalikan response JSON dengan status 422 dan daftar error. Di React kita bisa menangkapnya.

Bagian 3: Menangani Error Validasi dari Server

Ketika server mengembalikan error 422 (Unprocessable Entity), kita harus menampilkan pesan error ke pengguna. Di React, kita bisa parsing error response dan tampilkan dengan SweetAlert.

Contoh di catch block login:

} catch (error) {
  if (error.response?.status === 422) {
    const errors = error.response.data.errors;
    // Gabungkan semua pesan error
    const errorMessages = Object.values(errors).flat().join('\n');
    Swal.fire('Validasi Gagal', errorMessages, 'warning');
  } else if (error.response?.status === 401) {
    Swal.fire('Login Gagal', 'Email atau password salah', 'error');
  } else {
    Swal.fire('Error', 'Terjadi kesalahan server', 'error');
  }
}

Dengan ini, pengguna mendapat informasi jelas apa yang salah.

😆 "Validasi server itu kayak guru killer: kalau salah dikit, langsung disuruh ngulang!" 👩‍🏫

Bagian 4: Proteksi Rute di React (Private Route)

Kita sudah membuat PrivateRoute di tutorial #8. Sekarang kita perkuat dengan pengecekan role (misal hanya admin yang bisa akses route tertentu). Buat komponen RoleBasedRoute.

Contoh RoleBasedRoute.js:

import React from 'react';
import { Navigate } from 'react-router-dom';

function RoleBasedRoute({ children, allowedRoles }) {
  const token = localStorage.getItem('token');
  const user = JSON.parse(localStorage.getItem('user') || '{}');
  
  if (!token) {
    return <Navigate to="/login" />;
  }
  
  if (!allowedRoles.includes(user.role)) {
    return <Navigate to="/" />;
  }
  
  return children;
}

export default RoleBasedRoute;

Penggunaan di App.js:

<Route path="/dashboard" element={
  <RoleBasedRoute allowedRoles={['nasabah']}>
    <DashboardPage />
  </RoleBasedRoute>
} />

Pastikan data user disimpan di localStorage saat login (seperti yang kita lakukan).

Bagian 5: Penanganan Error Jaringan dan Server

Kadang server mati atau koneksi internet putus. Kita harus kasih tahu pengguna dengan pesan yang ramah.

Contoh interceptor Axios global (buat file baru, misal axiosConfig.js):

import axios from 'axios';
import Swal from 'sweetalert2';

axios.interceptors.response.use(
  response => response,
  error => {
    if (!error.response) {
      // Error jaringan
      Swal.fire('Koneksi Bermasalah', 'Tidak dapat terhubung ke server. Periksa internet Anda.', 'error');
    } else if (error.response.status >= 500) {
      Swal.fire('Server Error', 'Server sedang sibuk. Coba lagi nanti.', 'error');
    }
    return Promise.reject(error);
  }
);

Import file ini di index.js agar aktif global.

🛡️ Tips Keamanan Ekstra:
  • Bersihkan input dari tag HTML (di Laravel pakai strip_tags atau htmlspecialchars).
  • Gunakan HTTPS di production.
  • Simpan token di httpOnly cookie (lebih aman) daripada localStorage. Tapi untuk tutorial, localStorage OK.

Bagian 6: Demo Peningkatan Keamanan

Coba akses dashboard tanpa login: akan redirect ke login. Coba akses dashboard sebagai admin (jika admin login) tapi karena kita set allowedRoles=['nasabah'], dia akan ditendang. Coba kirim form dengan email tidak valid, muncul SweetAlert peringatan.

Semua ini membuat aplikasi kita lebih profesional dan aman.

Kesimpulan

  • ✅ Validasi client membuat pengguna langsung tahu kesalahan.
  • ✅ Validasi server memastikan data aman meskipun client diakali.
  • ✅ Penanganan error yang baik meningkatkan pengalaman pengguna.
  • ✅ Proteksi rute menjaga halaman hanya untuk yang berhak.

Dengan selesainya tutorial #11, aplikasi kita sudah cukup kokoh. Tutorial berikutnya (#12: Testing dan Deployment) akan membahas bagaimana menguji aplikasi dan menaikkannya ke internet. Sampai jumpa!

Lebih baru Lebih lama

نموذج الاتصال