Asp.NET Core Identity – Belli Sayıdaki Başarısız Girişlerde Kullanıcı Hesabını Kilitleme – X
Merhaba,
Asp.NET Core uygulamalarında bilgi bazlı gizliliği sağlayabilmek ve gelen kullanıcıları tarafımızca tanımlayabilmek için Identity mekanizmasıyla süreçte doğrulama yapılarını devreye sokuyoruz ve uygulamalarımızın bu şekilde tanımlı kimlikler eşliğinde güvencesini sağlamış oluyoruz. Tabi güvence bir tek kullanıcı yönetimiyle sağlanmamakta, doğrudan ya da dolaylı yoldan birçok yapılanma ile uygulama genel geçer koruma kalkanlarıyla dış dünyaya karşı güvenilirliği sağlamaktadır. Bu içeriğimizde Asp.NET Core Identity yazı dizimizin 10. makalesi olarak şuana kadar oluşturduğumuz yapılanmanın üzerine olası bir artniyetli saldırıya karşılık belli sayıdaki başarısız giriş denemesi neticesinde stratejik olarak alınan kullanıcının hesabını kilitleme önlemi üzerine istişare ediyor olacağız.
Herşeyden önce içeriğimizde bizlere eşlik edecek olan baş aktör metotlarımızı tanıyalım;
- IsLockedOutAsync
Kullanıcının kilitli olup olmadığını kontrol eden metottur. - AccessFailedAsync
Kullanıcının her başarısız oturum girişiminde veritabanındaki AccessFailedCount kolonunun değerini +1 arttırır. - ResetAccessFailedCountAsync
Kullanıcı başarılı giriş yaptığı taktirde “AccessFailedAsync” metodu ile arttırılan AccessFailedCount kolonundaki değeri sıfırlar. - SetLockoutEndDateAsync
Kullanıcı hesabını kilitlersek eğer kilitleme süresinin vadesini belirten metotdur. - GetAccessFailedCountAsync
Kullanıcının başarısız oturum açma sayısının eşiğini belirlediğimiz metottur.
Operasyonel olarak kullanacağımız metotları tanıdıktan sonra artık “User(Controller).cs” controller sınıfının altındaki “Login” actionına gidebilir ve aşağıdaki geliştirmeyi yapabiliriz.
public class UserController : Controller { readonly UserManager<AppUser> _userManager; readonly SignInManager<AppUser> _signInManager; public UserController(UserManager<AppUser> userManager, SignInManager<AppUser> signInManager) { _userManager = userManager; _signInManager = signInManager; } [HttpPost] public async Task<IActionResult> Login(LoginViewModel model) { if (ModelState.IsValid) { AppUser user = await _userManager.FindByEmailAsync(model.Email); if (user != null) { //İlgili kullanıcıya dair önceden oluşturulmuş bir Cookie varsa siliyoruz. await _signInManager.SignOutAsync(); Microsoft.AspNetCore.Identity.SignInResult result = await _signInManager.PasswordSignInAsync(user, model.Password, model.Persistent, model.Lock); if (result.Succeeded) { await _userManager.ResetAccessFailedCountAsync(user); //Önceki hataları girişler neticesinde +1 arttırılmış tüm değerleri 0(sıfır)a çekiyoruz. if (string.IsNullOrEmpty(TempData["returnUrl"] != null ? TempData["returnUrl"].ToString() : "")) return RedirectToAction("Index"); return Redirect(TempData["returnUrl"].ToString()); } else { await _userManager.AccessFailedAsync(user); //Eğer ki başarısız bir account girişi söz konusu ise AccessFailedCount kolonundaki değer +1 arttırılacaktır. int failcount = await _userManager.GetAccessFailedCountAsync(user); //Kullanıcının yapmış olduğu başarısız giriş deneme adedini alıyoruz. if (failcount == 3) { await _userManager.SetLockoutEndDateAsync(user, new DateTimeOffset(DateTime.Now.AddMinutes(1))); //Eğer ki başarısız giriş denemesi 3'ü bulduysa ilgili kullanıcının hesabını kilitliyoruz. ModelState.AddModelError("Locked", "Art arda 3 başarısız giriş denemesi yaptığınızdan dolayı hesabınız 1 dk kitlenmiştir."); } else { if (result.IsLockedOut) ModelState.AddModelError("Locked", "Art arda 3 başarısız giriş denemesi yaptığınızdan dolayı hesabınız 1 dk kilitlenmiştir."); else ModelState.AddModelError("NotUser2", "E-posta veya şifre yanlış."); } } } else { ModelState.AddModelError("NotUser", "Böyle bir kullanıcı bulunmamaktadır."); ModelState.AddModelError("NotUser2", "E-posta veya şifre yanlış."); } } return View(model); } } . . . diğer actionlar . . .
Yukarıdaki kod bloğunu incelerseniz eğer;
25. satırda giriş yapan kullanıcıya dair önceden yapmış olduğu hatalı giriş denemelerine istinaden arttırılmış olma ihtimali olan AccessFailedCount kolonundaki değeri “ResetAccessFailedCountAsync” metoduyla sıfırlıyoruz. 33. satırda ise kullanıcının yapmış olduğu her hatalı giriş denemesi neticesinde “AccessFailedAsync” metodu ile AccessFailedCount kolonundaki değer +1 arttırılmaktadır. Bu noktadan itibaren kullanıcının yapmış olduğu hatalı giriş sayısına göre bir hesap kilitleme yaptırımı uygulayabilmek için 35. satırda “GetAccessFailedCountAsync” metodu ile AccessFailedCount kolonundaki değeri elde ediyoruz ve hemen ardından yapılan if kontrolü eşliğinde eğer ki hatalı giriş kontrolü 3’e eşitse(opsiyoneldir, kendinize göre değiştirebilirsiniz) 38. satırda olduğu gibi “SetLockoutEndDateAsync” metodu ile kullanıcının hesabını belirtilen süre kadar kilitliyoruz. 43. satırda ise kullanıcının giriş yaptığına dair bilgi taşıyan “SignInResult” türünden “result” referansımızın “IsLockedOut” propertysi aracılığıyla bu kullanıcı hesabının kilitlenip kilitlenmediğine dair bilgi alıyoruz ve ona göre ModelState nesnesine hata mesajları ekliyoruz.
Bu işlemden sonra sıra uygulamayı ayağa kaldırıp hatalı oturum taleplerindeki süreci izlemeye geldi;
Yukarıdaki ekran alıntısına göz atarsanız eğer; ne zaman ki kullanıcı yanlış oturum açma işleminde bulunuyor o zaman “AccessFailedCount” kolonu +1 arttırılıyor. İlgili kolon 3 eşiğine geldiği taktirde uygulama kullanıcı hesabını kilitliyor ve “LockoutEnd” kolonuna bu kilitleme vadesini tarihsel olarak kaydediyor.
İşte bu kadar basit…
Asp.NET Core Identity yazı dizimizin bir sonraki içeriğinde görüşmek üzere…
İlgilenenlerin faydalanması dileğiyle…
İyi çalışmalar…
Not : Örnek projeyi indirmek için buraya tıklayınız.
İyi günler, ben daha basit bir proje için bunu kullanmak istiyordum mesela sadece 2 tablo(Kullanıcı ve rol tabloları ile)ile bunları yapamaz mıyız? Mvcde roleprovide ile kolaylıkla yapılabiliyordu ancak burda çok fazla detay var. Bunun için daha kolay bir yöntem var mıdır? Kusura bakmayın biraz saçma gelebilir söylediklerim ancak ben öğrenciyim o yüzden daha basit bir şey için lazımdı teşekkürler tekrardan.
Merhaba,
Bu içerik bir yazı dizisinin parçası olduğundan dolayı mümkün mertebe detaylandırılmış bir anlatıma sahiptir. Neticede bu detayın özeti esasında sizin kullandığınız kolay yöntemin ta kendisi 🙂 Sadece burada “Starup.cs” sınıfı üzerinden yapılan modüler bir konfigürasyonla birlikte birkaç ufak tefek değişikliğin dışında yapı yine aynı yapı olduğuna dikkatinizi çekerim…
Sevgiler…
Hocam konu ile alakalı ControllerBase.TryUpdateModelAsync
diye bir metodu gördüm yukardi kodlarla aynı işi yapıyor sanıyorsam
hocam merhaba. Çok faydalı bir yazı. Sadece bir şey belirtmek istiyorum(yanlışsam düzeltin); hatalı parola giriş yaptığımızda 21’inci satırdaki “PasswordSignInAsync” metodu çalıştığı anda bizim databasedeki AccessFailedCount +1 oluyor. birde 33’üncü satırdaki AccessFailedAsync metodunu çağırdığımız da +1 oluyor. yani toplamda bir hatalı girişte; databasedeki AccessFailedCount, 2 ye yükselmiş oluyor.
Merhaba,
AccessFailedAsync
metodu tetiklenmediği sürece access failed count(hatalı giriş sayısı) +1 artmaz! DolayısıylaPasswordSignInAsync
metodunda istediğiniz kadar hatalı giriş deneyin,AccessFailedAsync
‘ı iradenizle tetiklemediğiniz sürece artmayacaktır!evet hocam o satırı eklediğimizde mücteba hocamın dediği şekilde hata sayısı bir fazla oluyor. Emekleriniz için çok teşekkür ederim