Asp.NET Core Identity – UserManager Sınıfı İle Kullanıcı Yönetimi – V
Merhaba,
Asp.NET Core Identity yazı dizimizin 5. adımı olan bu içeriğimizde UserManager sınıfı ile kullanıcı yönetimi üzerine inceleme gerçekleştireceğiz. Önceki yazılarımızda kullanıcılarımızı modellediğimiz IdentityUser ve o kullanıcılara biçilen rolleri tanımladığımız IdentityRole sınıflarının ne olduğunu ele almış ve nasıl kullanıldıklarını detaylıca incelemiştik. Şimdi sıra bu yapılanmaları kullanarak kullanıcı oluşturmamızı ve var olan kullanıcıları yönetmemizi sağlayan UserManager sınıfını ele almaya gelmiştir.
UserManager Sınıfı
Uygulama üzerinde a’dan z’ye kullanıcı yönetimini gerçekleştirmemizi sağlayan sınıftır.
UserManager sınıfı hangi kullanıcı türünü yöneteceğini generic özelliğinden bilmek ister. Dolayısıyla ilgili sınıfın yapısını şöyle bir incelersek eğer;
görüldüğü üzere generic parametreye verilen IdentityUser türevi sınıf hangisiyle sistemde ona dair bir kullanıcı yönetimi söz konusu olacaktır.
Bu sınıfa erişebilmek için Asp.NET Core Identity mimarisinin kullanıldığı uygulamalarda Dependency Injection(DI Kaynak, DI Başka Bir Kaynak) ile talepte bulunmamız yeterli olacaktır.
public class UserController : Controller { readonly UserManager<AppUser> _userManager; public UserController(UserManager<AppUser> userManager) { _userManager = userManager; } }
Bu işlem neticesinde artık “AppUser” modeline özel UserManager sınıfını kullanabilmekte ve aşağıdaki metotlar ve propertyler eşliğinde tüm yönetimi sağlayabilmekteyiz.
Ben burada UserManager sınıfı içerisindeki bazı metot ve propertylerin görselini çekmiş bulunmaktayım. Şöyle rastgele göz atarsanız eğer göreceksiniz ki renkli kareler içerisine alınan tüm memberlar genel anlamda tüm kullanıcılara erişebilmeyi(select) ve bunların yanında kullanıcı oluşturmayı(insert), silmeyi(delete) ve güncellemeyi(update) sağlayan işlevselliğe sahiptirler. Bunların dışında şartlı sorgular oluşturan ve hususi bir kullanıcı odaklı çalışmamızı sağlayan metotlarda mevcuttur. Buradan anlayacağınız UserManager sınıfı kullanıcı yönetimiyle ilgili ana karargah görevi gören bir sorumluluğa sahiptir.
UserManager sınıfı kullanıcı yönetiminin ana karargahıdır.
İçeriğimizin bu noktasına kadar baş aktör olarak UserManager sınıfını yeterince teorik olarak ele almış bulunmaktayız. Artık olayı biraz daha somutlaştırmalı ve son noktaya doğru yaklaşırken örnek mahiyetinde ilgili yapıya imza atmalıyız. Bunun için ise ben kullanıcı oluşturma ve listeleme üzerine bir örneklendirme yapmayı tercih ediyorum.
Kullanıcı Oluşturma ve Listeleme
Şimdi kullanıcı bilgilerini alabileceğimiz örnek bir sayfa tasarlayacağız. Tabi bu örneği Asp.NET Core MVC uygulamasında geliştireceğimizden dolayı ilgili sayfanın modeli kullanıcı modeline karşılık gelen “AppUser” sınıfı olmalıdır. Olmalıdır diyorum çünkü UserManager sınıfı “AppUser” modeli üzerinden tüm kullanıcı yönetimi sağlayacaktır. Lakin “AppUser” sınıfının “IdentityUser” sınıfından türemesinden dolayı bu miras neticesinde gelen tüm propertylere karşılık kullanıcı kaydı esnasında bir değer verilmesi gerekecektir. Tabi bizler bu örneğimizde sadece kullanıcıdan kullanıcı adı(UserName), e-posta(Email) ve şifre(PasswordHash) bilgilerini isteyeceğimizden dolayı süreçte bu verisel trafiğe eşlik edecek ViewModel tasarlamamız gayet yerinde ve yeterli olacaktır. ViewModel yapılanmasının ne olduğuna dair detaylı bilgi edinmek istiyorsanız AutoMapper üzerine kaleme almış olduğum şu adresteki makaleyi inceleyebilirsiniz. İlgili makale içerisinde ViewModel yapılanmasına dair tüm senaryolar eşliğinde detaylı açıklamalar barındırmakla beraber ekstra olarak dolaylı yoldan bu içeriğimizede katkıda bulunacaktır.
Şimdi “Models” klasörü içerisinde “ViewModels” isminde bir klasör oluşturarak içerisine “AppUserViewModel” isminde class oluşturalım ve aşağıdaki gibi inşa edelim.
public class AppUserViewModel { [Required(ErrorMessage = "Lütfen kullanıcı adını boş geçmeyiniz...")] [StringLength(15, ErrorMessage = "Lütfen kullanıcı adını 4 ile 15 karakter arasında giriniz...", MinimumLength = 4)] [Display(Name = "Kullanıcı Adı")] public string UserName { get; set; } [Required(ErrorMessage = "Lütfen emaili boş geçmeyiniz...")] [EmailAddress(ErrorMessage = "Lütfen email formatında bir değer belirtiniz...")] [Display(Name = "Email")] public string Email { get; set; } [Required(ErrorMessage = "Lütfen şifreyi boş geçmeyiniz...")] [DataType(DataType.Password, ErrorMessage = "Lütfen şifreyi tüm kuralları göz önüne alarak giriniz...")] [Display(Name = "Şifre")] public string Sifre { get; set; } }
Bu viewmodele dikkat ederseniz eğer salt bilgileri karşılayacak olan propertyler, süreçte verisel transferi sağlayacağımız “AppUser” nesnesinde tutarsızlığa mahal vermemek için eşleşecek olan propertyler ile aynı isimde olacak şekilde tasarlanmıştır. Ya da benzer mantıkla süreçte AutoMapper kütüphanesi ile otomatik eşleştirme gerçekleştirilebilir. Eee doğal olarak bu otomatik eşleştirmeyi property isimlerindeki benzerliklerden gerçekleştireceğinden yine doğru bir tasarım gerçekleştirmiş oluyoruz. Sadece “Şifre” propertysi hariç. Sebebini ileriki satırlarda anlayacaksınız. Ayrıca bilgilerini girecek olan kullanıcıyla direkt muhattap olan viewmodel nesnemiz olacağından dolayı data annotations yapılanmasıyla gerekli veri güvenliği sağlanmıştır.
Bu işlemden sonra “User(Controller).cs” isimli controller sınıfında “SignIn” isminde bir action oluşturalım ve View katmanındaki karşılığını aşağıdai gibi kodlayalım.
@model AspNetCoreIdentityExample.Models.ViewModels.AppUserViewModel @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers <h3>Üye Ol</h3> <hr /> <form asp-action="SignIn"> <table> <tr> <td colspan="3"><div asp-validation-summary="ModelOnly"></div></td> </tr> <tr> <td><label asp-for="UserName"></label></td> <td><input asp-for="UserName" /></td> <td><span asp-validation-for="UserName"></span></td> </tr> <tr> <td><label asp-for="Email"></label></td> <td><input asp-for="Email" /></td> <td><span asp-validation-for="Email"></span></td> </tr> <tr> <td><label asp-for="Sifre"></label></td> <td><input asp-for="Sifre" /></td> <td><span asp-validation-for="Sifre"></span></td> </tr> <tr> <td colspan="3"><input type="submit" value="Üye Ol" /></td> </tr> </table> </form>
Bu işlemden sonra bind edilmiş “AppUserViewModel” nesnesini post neticesinde backend’de aşağıdaki gibi karşılayalım.
public class UserController : Controller { readonly UserManager<AppUser> _userManager; public UserController(UserManager<AppUser> userManager) { _userManager = userManager; } public IActionResult Index() { return View(_userManager.Users); } [HttpGet] public IActionResult SignIn() { return View(); } [HttpPost] public async Task<IActionResult> SignIn(AppUserViewModel appUserViewModel) { if (ModelState.IsValid) { AppUser appUser = new AppUser { UserName = appUserViewModel.UserName, Email = appUserViewModel.Email }; IdentityResult result = await _userManager.CreateAsync(appUser, appUserViewModel.Sifre); if (result.Succeeded) return RedirectToAction("Index"); } return View(); } }
Yukarıdaki kod bloğunu incelerseniz eğer; “HttpPost” tipinden olan “SignIn” metodunun içerisinde gerekli validasyon kontrolü yapıldıktan sonra post edilen “AppUserViewModel” nesnesinden gelen verileri oluşturulan “AppUser” nesnesine transfer etmekte ve ilgili “AppUser” nesnesini UserManager nesnesi üzerinden “CreateAsync” metodu aracılığıyla veritabanına kaydetmekteyiz. Burada iki hususa dikkatinizi çekmek istiyorum; birincisi, post neticesinde gelen viewmodel içerisindeki “Sifre” propertysi “CreateAsync” içerisinde ikinci parametreye verilerek ilgili parolanın Hash algoritması ile şifrelenerek kaydedilmesi sağlanmaktadır. İşte buradaki işlem yüzünden viewmodel içerisinde şifreyi “AppUser/IdentityUser” içerisindeki “PasswordHash” propertysinden isim olarak benzersiz tanımlamış bulunmaktayız. İkinci olarak ise burada manuel olarak yapılan eşleştirmeyi Automapper kütüphanesini kullanarakta otomatik bir şekilde gerçekleştirebiliriz. Tabi bu çalışmayıda sizlere bırakmaktayım…
“Index” actionu içerisinde ise UserManager nesnesi üzerinden “Users” propertysi çağrılmıştır ve böylece tüm kullanıcılar ilgili action içerisinde listelenecektir. Eğer ki üyelik işlemi başarıyla sonuçlanırsa Index actionına yönlendirme yapılacaktır.
“Hoca örneklendirmede bootstrap kullanmadın, bari şu validation error mesajlarını dinamik eyle…” diyenleriniz olabilir 🙂 Eee hadi istiyorsunuz madem sizleri kırmayalım ve son olarak hata mesajlarını daha da dinamik hale getirip yazımızı sonlandıralım.
Bu işlem için “jquery”, “jquery.validate” ve “jquery.validate.unobtrusive” kütüphanelerinin projeye include edilmesi yeterli olacaktır. Bunun için; “Projeye Sağ Tıklayarak” -> “Add” -> “Client-Side Library…” kombinasyonunu takip ediniz.
Bu kombinasyon neticesinde açılan pencereye yukarıda ismi verilen kütüphaneleri yazınız ve “Install” butonuna tıklayınız.
![]() |
![]() |
Bu işlemler neticesinde uygulamadaki “wwwroot” klasörü altına ilgili kütüphaneler indirilmiş olacaktır. Şimdi tek yapmamız gereken bu kütüphaneleri “_Layout.cshtml” sayfasında uygun bir yere ekleyerek html’e include etmektir.
<!DOCTYPE html> <html> <head> <script src="~/jquery/jquery.js"></script> <script src="~/lib/jquery-validate/jquery.validate.js"></script> <script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js"></script> </head> <body> <div> @RenderBody() </div> </body> </html>
Bu işlemden de sonra uygulamayı derleyip çalıştırdığımızda aşağıdaki ekran görüntüsünde olduğu gibi bir işlevle karşılaşmaktayız…
Evet… Bu makalemizde de kullanıcıları tüm yönleriyle yönetmemizi sağlayan UserManager sınıfının nasıl kullanıldığına dair detaylı bir inceleme yaptığımızı düşünüyorum. Bir sonraki yazı dizimizin devamı niteliğindeki makalemizde bu içeriğimizdeki şifre doğrulama validasyonu üzerine odaklanacağımızı bilmenizi isterim. O halde şimdilik görüşmek üzere…
İlgilenenlerin faydalanması dileğiyle…
İyi çalışmalar…
Not : Örnek projeyi indirmek için buraya tıklayınız.
Merhaba gencay hocam,
Dependency Injection kullanmadan bunu manager kullanamazmıyız.
UserManager _userManager = new UserManager();
Bu şekilde kullanmamıza izin vermiyor bunu bu şekilde nasıl kullanabiliriz.
Dependency Injection ile kullanmak istememenizin nedenini sorabilir miyim?
Merhaba hocam,
Şuan bir projede bu yapıyı Business Layer katmanında kullanmam gerekiyor. Onun için gerekli. Api yada normal web sayfasında değil.
public UserManager _userManager = new UserManager(new UserStore(new DatabaseContext()),null,null, null, null, null, null, null, null);
bu şekilde oluşturuyorum ancak usermanager fonksiyonlarını çalıştıramıyorum ancak
public RoleManager _roleManager = new RoleManager(new RoleStore(new DatabaseContext()), null, null, null, null);
rol manager da kullandığımda hata almıyorum. Sadece user managerda hata alıyorum çözemedim bir türlü.
Merhaba,
Dependency Injection ile ilgili nesneleri çekmeyi deneyiniz.
O işime yaramıyor hocam. Bir yolu vardır ama nasıl. Neyse cevap için teşekkürler
@Borahan,
Nihayetinde ilgili Business Layerı web uygulamasıyla bileşik bir şekilde kullanmıyor musun? Lazım olan noktada webde Dependency Injection ile elde edilen nesneyi BL’ye gönderebilirsin.
Neyse, kolay gelsin.
Yok hocam Business Layer ayrı bir katmanda, gerektiğinde api için gerektiğinde web için belki ilerde desktop için referans verip kullanılıyor. Buna bir cevap bulabilirsem buraya da yazarım belki başka ihtiyacı olan çıkar.
Evet öylede olması gerekiyor zaten. Burada bileşiklikten kastım dll olarak web uygulamasına referans ediyorsun. Nihayetinde bu referans ilişkisi neticesinde web uygulamasından ilgili Business’da ki classa nesne gönderebilmek için dependency injection ile çekip, constructer’dan yahut farklı bir property üzerinden ilgili katmana veri gönderilebilir.
Yani anlatmak istediğim şu ki;
Business’ın istediği nesneyi Presentation Layer’da elde et ve oradan BL’ye gönder. Muhtemelen PL olarak Asp.NET Core uygulaması kullandığından dolayı Dependency Injection ile ilgili nesneyi rahatça orada elde edebilir ve hangi katmanda kullanacaksan oraya gönderebilirsin.
Hocam sorunun çözümünü buldum. Herhangibir katmanda User Managerı yeniden üretmek için aşağıdaki kod yeterli. Sorun UserStore ve PasswordHasher birlikte üretmek
Burada da sormuştum.
Referans link: https://github.com/aspnet/AspNetCore/issues/16926
Ellerine sağlık 🙂 Teşekkürler geri dönüşün için.
Borahan merhaba,
Bende bir attribute içerisinde usermanagerı kullanmak istiyorum. Bulduğun yöntem oluyor gibi ancak ben DatabaseContext tarafında hata oluyorum. Bunun yerine DBContexti seçtiğimde parametre istiyor. Aşağıdaki gibi yaptığımdada bu sefer usermanagerda userı doldurmuyor Ben şu anda net core 3.1 kullanmaktayım. Bunu orada nasıl geçebilirim. Bir yorumun var mıdır ?
Hocam merhaba;
IdentityResult result = await _userManager.CreateAsync(user, users.Password).Result;
user hata veriyor ..
“The name ‘user’ does not exist in the current context”
Core 2.2
Çözümünü nasıl yapabilirim hocam
Merhaba;
kodunu
şeklinde değiştiriniz.
Ayriyetten bu kodun kullanıldığı metodu async keywordü ile işaretlemeyi ve geriye Task< T > türevinde bir değer döndürmeyi unutmayınız.
Kolay gelsin.
Yaptım ama gene aynı hata alıyorum.
Doğru ya… Biz yanlış yere odaklanmışız. _userManager.CreateAsync metodunda kullandığınız “user” referanslı CustomIdentityUser nesnesini siz manuel oluşturmayacaksınız aksi taktirde contextte böyle bir userın olmadığına dair hata alırsınız. İlgili kullanıcıyı UserManager sınıfı aracılığıyla _userManager.FindByIdAsync(…) vs. şeklinde metotlar ile context üzerinden elde etmeniz gerekmektedir.
Hocam merhaba;
UserManager userManager1;
olarak tanımladım.
IdentityResult result = await _userManager1.CreateAsync(user, users.Password);
aynı hatayı aldım
Hocam çok pardon 🙂 geçe geçe yanlışlık yapmışım.
Bu şekilde olacaktı.
Hocam merhaba arayıpta bulamadığım bir şeyi size sormak istiyorum, kayıtlarını aldığımız kullanıcıların hepsini nasıl listeleyebiliriz ? örneğin bir admin panelim var burada kullanıcıları listelemek aynı zamanda put,delet işlemlerini yapmak istiyorum geri dönüş yaparsanız memnun olurum.
Merhaba,
Aslında bu makalede bu sorunun cevabı mevcuttur. Tüm kullanıcıları listeleyebilmek için UserManager sınıfının Users propertysini kullanabilirsiniz.
Örneğin;
şeklinde olduğu gibi…
Ardından listeleme yaptığınız view üzerinden update ve delete işlemleri için gerekli yönlendirmeleri gerçekleştirebilirsiniz.
Kolay gelsin.
Merhabalar Hocam,
Identity server kullanarak AspNetUSers tablosune ekleme yaptığım ekstra alanı
HttpContext.Identity.Users.Name kullanarak kullanıcı adını çektiğimiz gibi Ekstra alanıda çekmenin bir yöntemi var mıdır ?
Merhaba,
Extension metotlarla bunu sağlayabilirsin. Aksi taktirde direkt olarak Identity mekanizmasında istediğin gibi her özelliği getiren bir özellik yoktur.
Hocam Merhabalar,
projemde IdentityServer kullanıyorum ve ekstra bir alan açtım bakiye adında.
Normalde login olduğu zaman sürekli loginliğini göstermek için ViewComponent kullanıyorum.
kullanarak viewComponentte hangi kullanıcı login ise userName ine ulaşabiliorum. AspNetUser Tablomda Bakiye alanına ulaşmak için şöyle bir kurgu yapabilirim diye düşünmüştüm;
Fakat Bakiyeye ulaşamıyorum. Bu işlemi burada yapmak zorundayım kullanıcı detay sayfasında her türlü bilgilerine ulaşıyorum AspNEtUsers tablosunun acaba HttpContext.User.Identity den sonra Bakiye alanına da burada ulaşabilirmiyim ?
Ekstra olarak şöyle bir yapı denedim belki olur diye olmadı ama istediğim mantık bu şekilde.
Yapmanız gereken UserManager nesnesini dependency injection ile constructor’dan talep edip ve ardından aşağıdakine benzer bir şekilde o an oturumu açık user’ı elde ederek istediğiniz property değerini kullanmanızdır.
Gencay hocam merhaba, gununuz hayirli ve hos gecsin. Bu yazinizda anlamadigim bir seyi rica etmek istiyordum beni aydinlatmaginizi.
______________________________________________
“Bu viewmodele dikkat ederseniz eğer salt bilgileri karşılayacak olan propertyler, süreçte verisel transferi sağlayacağımız “AppUser” nesnesinde tutarsızlığa mahal vermemek için eşleşecek olan propertyler ile aynı isimde olacak şekilde tasarlanmıştır. Ya da benzer mantıkla süreçte AutoMapper kütüphanesi ile otomatik eşleştirme gerçekleştirilebilir. Eee doğal olarak bu otomatik eşleştirmeyi property isimlerindeki benzerliklerden gerçekleştireceğinden yine doğru bir tasarım gerçekleştirmiş oluyoruz. Sadece “Şifre” propertysi hariç. Sebebini ileriki satırlarda anlayacaksınız.”
>>>>>>>>>>>>>>>>>> ileriki satırlarda anlatiminiz:
“Burada iki hususa dikkatinizi çekmek istiyorum; birincisi, post neticesinde gelen viewmodel içerisindeki “Sifre” propertysi “CreateAsync” içerisinde ikinci parametreye verilerek ilgili parolanın Hash algoritması ile şifrelenerek kaydedilmesi sağlanmaktadır. İşte buradaki işlem yüzünden viewmodel içerisinde şifreyi “AppUser/IdentityUser” içerisindeki “PasswordHash” propertysinden isim olarak benzersiz tanımlamış bulunmaktayız.”
______________________________________________
Sormak istediyim o idiki, ViewModel sinifinizde siz property ismini Sifre yapmissiniz, yukarida yazdigim sebebden dolayi, ama ben yinede anlayamadim niye PasswordHash deyilde Sifre koydunuz property ismini ? cunki, su an mesela kendimde Sifre yerine PasswordHash yaptim ViewModeldeki property ismini ve problemsiz calisti: https://i2.paste.pics/5162b51db9b07037cfead9a5621672ae.png . Yakalayamadim olay su, property isminin neden PasswordHash ile ust-uste dusmemeli oldugu?
– Yazi icin cok sagolun hocam, her yazinizda oldugu gibi cook sade ve anlasilir dilde yazilmis.
sorumda yeni satirlara gecme komutu uygulanmamis gibi gozukuyor, boylede okumasi zor, ondan dolayi buraya yapistirdim sorunu 🙁
Selam Adil,
Property isminin ne olduğu hiç önemli değil. İstersen ‘Ahmet’ koy 🙂 Burada mühim olan neyi, nerede, ne amaçla çağırdığını bilmek.
Sevgiler.
Sagolun cevap icin, her yaziniz bize yeni bir sey katiyor, bir daha tesekkurler.
mvc projesinde [Authorize] altındaki sayfalara token bazlı identity server yetkilendirmeyi bir türlü çalıştıramadım. çok fazla şey denedim. yok ne yaptıpsam login sıkıntısını aşamadım. bununla ilgili sizin yukarıdaki şeyleri de denedim. token alıyorum orada sıkıntı yok, ama Http tarafında yetkinin verildiğini siteye nasıl tanıtacağım. token geldi artık yetki alındı actionun içine girebilirsini nasıl tanıtıyoruz. bi örnek yapabilirseniz süper olur.
Merhaba Hocam bende kodlar çalıştı fakat şifreyi yanlış girdiğimde yada olmayan bir kullanıcıyla giriş yapmak istediğimde hata mesajlarını göstermiyor ne yapabilirim ?
Merhaba,
Uğur örnek bir kod vs. paylaşmadan direkt -ne yapabilirim- diye sorduğun için şöyle cevaplayacağım.
Kodlarını iyi gözden geçirebilir ve böylece muhtemelen yapmış olduğun bir mantık hatasını onarabilirsin.
İyi çalışmalar…