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?
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.
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.
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.
- Bersihkan input dari tag HTML (di Laravel pakai
strip_tagsatauhtmlspecialchars). - 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!