Session Auth Manual: Auth::attempt
Pahami cara kerja login di balik layar Breeze.
Apa yang Sebenarnya Dilakukan Auth::attempt
Breeze itu nyaman, tapi kalau kamu tidak paham apa yang terjadi di balik layarnya, kamu akan bingung saat harus menulis login custom (misal login pakai username, atau login multi-guard). Intinya cuma satu baris: Auth::attempt(). Method ini mencari user berdasarkan kredensial non-password (biasanya email), lalu memverifikasi password dengan Hash::check() yang memakai bcrypt. Kalau cocok, user "diingat" di session untuk request-request berikutnya.
// app/Http/Controllers/AuthController.php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class AuthController extends Controller
{
public function login(Request $request)
{
$credentials = $request->validate([
'email' => 'required|email',
'password' => 'required|string',
]);
// parameter kedua = remember me (cookie 5 tahun, aman)
if (Auth::attempt($credentials, $request->boolean('remember'))) {
$request->session()->regenerate();
return redirect()->intended('/dashboard');
}
return back()->withErrors([
'email' => 'Email atau password salah.',
])->onlyInput('email');
}
}Perhatikan $request->session()->regenerate() tepat setelah login sukses. Ini bukan opsional. Tanpa itu, attacker yang berhasil menanam session ID ke browser korban sebelum login (session fixation) bisa memakai session ID yang sama setelah korban login. Regenerate membuat session ID lama hangus seketika.
Kredensial Tambahan
attempt() menerima kondisi tambahan selain email dan password. Ini berguna untuk memblokir akun non-aktif tanpa query manual:
if (Auth::attempt(['email' => $email, 'password' => $password, 'is_active' => true])) {
// ...
}Laravel otomatis mengecualikan password dari klausa WHERE dan memakainya hanya untuk verifikasi hash. Syarat tambahannya harus berupa perbandingan = sederhana di kolom tabel users.
Logout yang Benar
Logout bukan sekadar Auth::logout(). Tiga langkah ini adalah paket wajib:
public function logout(Request $request)
{
Auth::logout(); // hapus user dari session
$request->session()->invalidate(); // hanguskan seluruh data session
$request->session()->regenerateToken(); // ganti CSRF token
}invalidate() memastikan tidak ada sisa data session yang bisa dipakai ulang, dan regenerateToken() mencegah token CSRF lama dipakai untuk serangan replay. Kalau kamu cuma memanggil Auth::logout(), session ID lama masih hidup dan data session masih ada.
Cek Status Login di Mana Saja
// di controller / Blade / middleware
Auth::check(); // true kalau sedang login
Auth::user(); // model User yang login (null kalau tamu)
Auth::id(); // id user, tanpa load model (lebih hemat)
// di Blade
@auth
<p>Halo, {{ auth()->user()->name }}</p>
@endauth
@guest
<a href="/login">Masuk</a>
@endguestPakai Auth::id() kalau kamu cuma butuh id untuk query, jangan Auth::user()->id yang me-load seluruh model user tanpa perlu.
Jebakan Umum
Pertama, membandingkan password secara manual dengan === atau md5(). Jangan pernah. Password di database disimpan sebagai bcrypt hash satu arah, satu-satunya cara verifikasi yang benar adalah Hash::check() dan Auth::attempt() sudah melakukannya untukmu.
Kedua, lupa @csrf di form login. Tanpa token CSRF, POST login ditolak dengan 419 dan user mengira passwordnya salah. Ketiga, pesan error yang membocorkan informasi: "email tidak terdaftar" vs "password salah" memberi tahu attacker email mana yang valid. Pakai satu pesan generik untuk keduanya, seperti yang dilakukan Breeze.
Keempat, me-redirect ke URL dari input user tanpa validasi setelah login (open redirect). redirect()->intended() aman karena hanya memakai URL yang sebelumnya disimpan Laravel saat middleware auth melempar user, bukan dari parameter request mentah.
Catatan teknis: Session auth cocok untuk aplikasi web tradisional di mana browser dan server berada dalam satu aplikasi. Begitu client-mu terpisah (mobile app, SPA di domain lain), session cookie menjadi masalah dan kamu butuh token stateless seperti Sanctum. Pahami batas ini sebelum memaksa session ke arsitektur yang salah.
Tantangan
Login Custom
Tanpa Breeze, buat form login manual: route GET/POST /masuk, controller dengan Auth::attempt, redirect ke /dashboard saat sukses, error saat gagal. Test dengan user dari seeder.