ASP.NET Core API #12: Membuat Fitur Login dengan Hashing Password (BCrypt) Tanpa JWT
Halo lagi, calon developer API yang sadar keamanan!
Di artikel sebelumnya (#11) kita membuat login dengan password plain text — itu ibarat menyimpan kunci rumah di bawah keset, sangat tidak aman! Sekarang kita akan meningkatkan keamanan dengan meng-hash password menggunakan BCrypt. Password akan disimpan dalam bentuk terenkripsi (hash) sehingga meskipun database bocor, password asli tidak langsung diketahui. Tapi kita masih belum menggunakan JWT; kita hanya akan mengembalikan pesan sukses. Fokus di sini adalah penyimpanan password yang aman.
Apa yang Akan Kita Buat?
- Mengubah model
User: kolomPasswordakan menyimpan hash, bukan plain text. - Menginstal package BCrypt.Net-Next untuk hashing.
- Memodifikasi endpoint register agar meng-hash password sebelum disimpan.
- Memodifikasi endpoint login agar memverifikasi password dengan hash yang tersimpan.
- Data user yang sudah ada (plain text) perlu di-update atau buat baru.
- Uji coba dengan Postman.
Langkah 1: Install Package BCrypt
Buka Package Manager Console (Tools → NuGet Package Manager → Package Manager Console). Jalankan perintah:
Install-Package BCrypt.Net-Next
Atau jika menggunakan .NET CLI:
dotnet add package BCrypt.Net-Next
Package ini menyediakan fungsi BCrypt.HashPassword() dan BCrypt.Verify().
Langkah 2: Update Model User (Tidak Ada Perubahan Struktural)
Secara struktural, model User tetap sama karena kita tetap menyimpan string di kolom Password. Bedanya, string tersebut sekarang akan berisi hash, bukan plain text. Jadi tidak perlu migration baru. Tapi kita perlu memperbarui data user yang ada.
Langkah 3: Modifikasi Endpoint Register
Buka AuthController.cs. Ubah method Register menjadi:
[HttpPost("register")]
public async Task<IActionResult> Register(RegisterDto registerDto)
{
// Cek apakah username sudah ada
if (await _context.Users.AnyAsync(u => u.Username == registerDto.Username))
{
return BadRequest(new { message = "Username sudah digunakan." });
}
// Hash password sebelum disimpan
string passwordHash = BCrypt.Net.BCrypt.HashPassword(registerDto.Password);
var user = new User
{
Username = registerDto.Username,
Password = passwordHash // simpan hash, bukan plain text
};
_context.Users.Add(user);
await _context.SaveChangesAsync();
return Ok(new { message = "Registrasi berhasil." });
}
Penjelasan: BCrypt.HashPassword() menghasilkan string hash yang sudah termasuk salt secara otomatis. Jadi kita tidak perlu menyimpan salt terpisah.
Langkah 4: Modifikasi Endpoint Login
Ubah method Login menjadi:
[HttpPost("login")]
public async Task<IActionResult> Login(LoginDto loginDto)
{
// Cari user berdasarkan username
var user = await _context.Users
.FirstOrDefaultAsync(u => u.Username == loginDto.Username);
if (user == null)
{
return Unauthorized(new { message = "Username atau password salah." });
}
// Verifikasi password yang dikirim dengan hash di database
bool isValid = BCrypt.Net.BCrypt.Verify(loginDto.Password, user.Password);
if (!isValid)
{
return Unauthorized(new { message = "Username atau password salah." });
}
// Login sukses (tanpa token)
var response = new LoginResponseDto
{
Id = user.Id,
Username = user.Username,
Message = "Login berhasil."
};
return Ok(response);
}
BCrypt.Verify() akan membandingkan password plain text dengan hash, mengembalikan true jika cocok.
Langkah 5: Membersihkan Data Lama (Opsional)
Jika sudah ada data user dengan plain text, kita perlu menghapusnya atau memperbaruinya dengan hash. Bisa melalui SQL atau buat migration data. Untuk sementara, kita hapus saja data lama dan daftar ulang.
Di SSMS, jalankan:
DELETE FROM Users;
Atau jika ingin mempertahankan, kita bisa update manual dengan hash, tapi repot. Lebih baik daftar ulang.
Langkah 6: Uji Coba dengan Postman
Jalankan API (F5). Buka Postman.
1. Registrasi User Baru
- Method: POST
- URL:
https://localhost:7000/api/auth/register - Body (raw JSON):
{
"username": "joko",
"password": "rahasia123"
}
Response: { "message": "Registrasi berhasil." }
2. Cek Database
Lihat tabel Users, kolom Password akan berisi string panjang seperti $2a$11$... . Itu adalah hash BCrypt.
3. Login dengan password benar
- Method: POST
- URL:
https://localhost:7000/api/auth/login - Body:
{
"username": "joko",
"password": "rahasia123"
}
Response sukses:
{
"id": 1,
"username": "joko",
"message": "Login berhasil."
}
4. Login dengan password salah
{
"username": "joko",
"password": "salah"
}
Response 401 Unauthorized.
⚡ Keuntungan Menggunakan BCrypt
- Salt otomatis: Setiap hash unik meskipun password sama.
- Lambat secara sengaja: Mempersulit serangan brute force.
- Adaptif: Bisa ditingkatkan kekuatan hash-nya seiring waktu.
Bagaimana Cara Kerja BCrypt?
BCrypt menghasilkan hash dengan format: $2a$[cost]$[salt][hash]. Cost menentukan seberapa lambat proses hashing (default 10-12). Saat verifikasi, BCrypt membaca cost dan salt dari hash, lalu menghitung ulang dan membandingkan. Sangat praktis!
Masih Tanpa JWT, Tapi Lebih Aman
Sekarang password tersimpan aman, tapi kita masih belum menggunakan JWT. Artinya setelah login, kita tidak memberi token ke client. Client harus mengirim username/password lagi setiap kali akses endpoint yang dilindungi — ini tidak praktis dan tidak aman. Di sinilah JWT berperan. Tapi untuk pembelajaran, kita fokus dulu pada hashing.
Di artikel #7 dan #8 kita sudah membahas JWT. Kamu bisa menggabungkan hashing BCrypt dengan JWT untuk keamanan maksimal.
Selamat! Password Kamu Sekarang Tersimpan Aman
Dengan BCrypt, password user tidak lagi terlihat meskipun database bocor. Ini langkah penting menuju aplikasi yang profesional.
📌 Rangkuman
- BCrypt meng-hash password dengan salt otomatis.
- Gunakan
BCrypt.HashPassword()saat registrasi. - Gunakan
BCrypt.Verify()saat login. - Data user lama harus diperbarui karena hash berbeda.
Selanjutnya?
Kamu sekarang sudah memahami autentikasi dasar dan hashing. Untuk produksi, kombinasikan dengan JWT (lihat artikel #7 dan #8). Kamu juga bisa membuat endpoint logout, refresh token, dll.
Terima kasih telah mengikuti seri API ini. Semoga bermanfaat!
Ditulis oleh Kakak programmer yang dulu juga pakai plain text, lalu tobat setelah kena bobol. Kalau ada pertanyaan, tulis di komentar ya!