input('role') === 'siswa') { // ...maka validasi input 'nisn' dan 'password'. return [ 'nisn' => ['required', 'string'], 'password' => ['required', 'string'], ]; } // Jika tidak (untuk 'guru' dan 'penjaga perpus'), validasi 'email' dan 'password'. return [ 'email' => ['required', 'string', 'email'], 'password' => ['required', 'string'], ]; } /** * Mencoba untuk mengautentikasi kredensial dari request. * Ini adalah "otak" dari proses login yang berisi logika paling penting. * * @throws \Illuminate\Validation\ValidationException */ public function authenticate(): void { // Langkah 1: Pastikan pengguna tidak mencoba login terlalu sering (mencegah brute-force). $this->ensureIsNotRateLimited(); // Ambil data yang dikirim dari form login. $roleDariForm = $this->input('role'); $allUsers = DummyDataService::getAllSiswa(); $inputPassword = $this->input('password'); $userArray = null; // Tentukan field mana yang akan menerima pesan error jika gagal (nisn atau email). $errorField = $this->filled('nisn') ? 'nisn' : 'email'; // Langkah 2: Cari data pengguna berdasarkan input yang diberikan. if ($this->filled('nisn')) { // Jika form diisi dengan 'nisn', cari pengguna berdasarkan 'nisn'. $userArray = collect($allUsers)->firstWhere('nisn', $this->input('nisn')); } else { // Jika tidak, cari pengguna berdasarkan 'email'. $userArray = collect($allUsers)->firstWhere('email', $this->input('email')); } // Langkah 3: Lakukan Pengecekan Kredensial dan Role. // Cek #1: Apakah pengguna ditemukan DAN password yang dimasukkan cocok? if ($userArray && $userArray['password'] === $inputPassword) { // Cek #2: Jika kredensial benar, apakah role pengguna sesuai dengan form yang digunakan? if (isset($userArray['role']) && $userArray['role'] === $roleDariForm) { // --- SEMUA SYARAT TERPENUHI --- // Buat objek User dari data dummy. $userModel = new User(); $userArray['name'] = $userArray['nama_lengkap']; $userModel->forceFill($userArray); // Loginkan pengguna secara resmi ke dalam sistem. Auth::login($userModel); // Reset hitungan percobaan login yang gagal. RateLimiter::clear($this->throttleKey()); return; // Proses autentikasi berhasil. } else { // --- KASUS GAGAL: KREDENSIAL BENAR, TAPI ROLE SALAH --- // Tambah hitungan percobaan login yang gagal. RateLimiter::hit($this->throttleKey()); // Ambil nama role asli pengguna untuk ditampilkan di pesan error. $actualRole = Str::title($userArray['role'] ?? 'Tidak Dikenal'); // Lemparkan error validasi khusus 'forbidden' dengan pesan yang jelas. throw ValidationException::withMessages([ 'forbidden' => "Akses ditolak. Akun ini terdaftar sebagai {$actualRole}.", ]); } } // --- KASUS GAGAL: KREDENSIAL TIDAK COCOK --- // Jika pengguna tidak ditemukan atau password salah. RateLimiter::hit($this->throttleKey()); throw ValidationException::withMessages([ $errorField => trans('auth.failed'), // Pesan error umum "These credentials do not match...". ]); } /** * Memastikan request login tidak dibatasi karena terlalu banyak percobaan. */ public function ensureIsNotRateLimited(): void { // Jika percobaan belum melebihi 5 kali, lanjutkan. if (!RateLimiter::tooManyAttempts($this->throttleKey(), 5)) { return; } // Jika sudah lebih dari 5 kali, lemparkan error 'throttle'. event(new Lockout($this)); $seconds = RateLimiter::availableIn($this->throttleKey()); throw ValidationException::withMessages([ 'email' => trans('auth.throttle', [ 'seconds' => $seconds, 'minutes' => ceil($seconds / 60), ]), ]); } /** * Mendapatkan kunci throttle untuk request ini. * Kunci ini unik untuk setiap pengguna (berdasarkan nisn/email) dan alamat IP. */ public function throttleKey(): string { // Gunakan 'nisn' jika ada, jika tidak, gunakan 'email' sebagai identitas. $loginIdentifier = $this->input('nisn') ?: $this->input('email'); return Str::transliterate(Str::lower($loginIdentifier) . '|' . $this->ip()); } }