Yazılım Mimarileri ve Tasarım Desenleri Üzerine

Asp.NET Core Identity – UserManager Sınıfı İle Kullanıcı Yönetimi – V

Asp.NET Core Identity

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.

Exit mobile version