Derinlemesine yazılım eğitimleri için kanalımı takip edebilirsiniz...

Asp.NET Core Identity – RoleManager Sınıfı İle Rol Yönetimi – XIV

Merhaba,

Asp.NET Core Identity yazı dizimizin 14. makalesinde, uygulamamızda kullanıcıları belirli yetkiler doğrultusunda yönlendirebilmek ve sayfa odaklı erişim durumlarına müdahale edebilmek için rol yönetimi üzerine konuşacağız.

Rol Bazlı Yetkilendirme Nedir? Roles Based Authorization

Rol bazlı yetkilendirme, yukarıdaki giriş cümlesinde de ifade etmeye çalıştığım gibi kullanıcıların belli başlı sayfalara erişimini belirlememizi sağlayan ve bunun için roller tanımlayarak yetkilendirme yapmamıza imkan tanıyan bir stratejidir.

Şöyle basit bir örnekle metafor yaparsak eğer; ilaç almaya gittiğiniz eczanenin arka odasının kapısında “Personel Harici Giremez!” uyarısı görmüşsünüzdür. Ha işte, o odaya erişebilmek için o eczanede “Personel” rolüne sahip olmanız gerekmektedir. Eğer ki dışarıdan gelen müşteri iseniz ne yazık ki o odaya giremezsiniz.

Web uygulamalarında da benzer mantık geçerlidir ve kullanıcılara rol odaklı sayfa erişimleri sağlanmaktadır. Örneğin; Maliye bakanlığının otomasyonunda “Bütçe” sayfasına sade ve sadece “Director” ya da “Manager” rolüne sahip olan kullanıcılar erişebilirken, “Şehirler” sayfasına herkes erişebilmektedir.

RoleManager Sınıfı

Asp.NET Core Identity mekanizmasında uygulamaya dair tüm rol yönetimini RoleManager sınıfı üstlenmektedir. Rol ekleme, silme, güncelleme ve listeleme sorumluluklarını gerçekleştirmektedir.

IdentityRole Sınıfı İle Rol Entitysi Tanımlama

Uygulamada bir rol entitysi tanımlayabilmek için ilgili sınıfın “IdentityRole” sınıfından türemesi gerekmektedir.

    public class AppRole : IdentityRole<int>
    {
        public DateTime OlusturulmaTarihi { get; set; }
    }

Ve bu rol sınıfı uygulamadaki Context nesnesinin “IdentityDbContext” base classına aşağıdaki gibi bildirilmesi gerekmektedir.

    public class AppDbContext : IdentityDbContext<AppUser, AppRole, int>
    {
        public AppDbContext(DbContextOptions<AppDbContext> dbContext) : base(dbContext) { }
    }

Ayrıca yine ilgili sınıfın Startup dosyasında da AddIdentity fonksiyonu ile aşağıdaki gibi belirtilmesi gerekmektedir.

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddIdentity<AppUser, AppRole>(_ =>
            {
                .
                .
                .
            }
        }
Rol Oluşturma

Rol oluşturabilmek için RoleManager sınıfının “Create” metodunu aşağıdaki gibi kullanabiliriz.

    public class RoleController : Controller
    {
        readonly RoleManager<AppRole> _roleManager;
        public RoleController(RoleManager<AppRole> roleManager)
        {
            _roleManager = roleManager;
        }
        .
        .
        .
        [HttpPost]
        public async Task<IActionResult> CreateRole(RoleViewModel model)
        {
            IdentityResult result = await _roleManager.CreateAsync(new AppRole { Name = model.Name, OlusturulmaTarihi = DateTime.Now });
            if (result.Succeeded)
            {
                //Başarılı...
            }
            return View();
        }
    }
Rol Güncelleme

Oluşturulmuş rolü güncelleyebilmek için 16. satırda olduğu gibi “Update” metodunu kullanabiliriz.

    public class RoleController : Controller
    {
        readonly RoleManager<AppRole> _roleManager;
        public RoleController(RoleManager<AppRole> roleManager)
        {
            _roleManager = roleManager;
        }
        [HttpPost]
        public async Task<IActionResult> CreateRole(RoleViewModel model, string id)
        {
            IdentityResult result = null;
            if (id != null)
            {
                AppRole role = await _roleManager.FindByIdAsync(id);
                role.Name = model.Name;
                result = await _roleManager.UpdateAsync(role);
            }
            else
                result = await _roleManager.CreateAsync(new AppRole { Name = model.Name, OlusturulmaTarihi = DateTime.Now });

            if (result.Succeeded)
            {
                //Başarılı...
            }
            return View();
        }
    }
Rol Silme

Rol silmek istediğimizde ise Delete fonksiyonunu aşağıdaki gibi kullanmamız yeterlidir.

    public class RoleController : Controller
    {
        readonly RoleManager<AppRole> _roleManager;
        public RoleController(RoleManager<AppRole> roleManager)
        {
            _roleManager = roleManager;
        }
        .
        .
        .
        public async Task<IActionResult> DeleteRole(string id)
        {
            AppRole role = await _roleManager.FindByIdAsync(id);
            IdentityResult result = await _roleManager.DeleteAsync(role);
            if (result.Succeeded)
            {
                //Başarılı...
            }
            return RedirectToAction("Index");
        }
    }
Rolleri Listeleme

Tüm rolleri elde etmek ve listeleyebilmek için direkt olarak RoleManager nesnesinin Roles propertysini kullanabilirsiniz.

        public IActionResult Index()
        {
            return View(_roleManager.Roles.ToList());
        }
Kullanıcılara Rol Atama

Tanımlanmış rolleri uygulamadaki kullanıcılara atayarak bir nevi kullanıcı yetkilendirme işlemini gerçekleştirebilmek için UserManager nesnesinin AddToRole metodu kullanılmaktadır.

        public async Task<IActionResult> RoleAssign(string id)
        {
            AppUser user = await _userManager.FindByIdAsync(id);

            await _userManager.AddToRoleAsync(user, "Administrator");
            await _userManager.AddToRoleAsync(user, "Moderator");
            await _userManager.AddToRoleAsync(user, "Editor");
            await _userManager.AddToRoleAsync(user, "tor");
            return View();
        }

Burada dikkat edilmesi gereken husus her bir rolün önceden tanımlanmış olması gerekmektedir. Aksi taktirde hatayla karşılanacaktır.

Rol atamayı daha işlevsel olarak nasıl yapabiliriz? sorusunu sorduğunuzu duyar gibiyim…
Evet, sanırım uygulamada tanımlanmış/tanımlanacak rolleri yukarıdaki gibi statik olarak önceden tahmin etmenizi beklemek ve daha da tuhafı bu tanımlamaları tüm kullanıcılar için gerçekleştirmek yersiz olacaktır… Muhtemeldir ki sizde hak vereceksiniz buradaki en doğru aksiyon rol atamak istediğimiz kullanıcıya tıkladığımız zaman tüm rollerin listelenmesi ve hatta bu listede ilgili kullanıcıyla ilişkilendirilmiş önceki rollerin seçili gelmesi ve aralarından seçtiklerimizin ilgili kullanıcıyla ilişkilendirilmesi olacaktır.

Bunun için herşeyden önce hangi rolün seçildiğine dair bilgi taşıyacak olan ViewModeli geliştirmek gerekmektedir…

    public class RoleAssignViewModel
    {
        public int RoleId { get; set; }
        public string RoleName { get; set; }
        public bool HasAssign { get; set; }
    }

Yukarıdaki viewmodeli incelerseniz eğer role dair id ve name değerlerini tutmakla birlikte o anki rolün ilgili kullanıcıya atanıp atanmadığı bilgisini de(HasAssign) tutmaktadır. Şimdi yapmamız gereken kullanıcıya rol ekleme sayfası oluşturarak, tüm rolleri orada seçilebilir bir şekilde listelemek ve biryandan da kullanıcıyla ilişkili rol varsa işaretli bir şekilde getirmektir. Akabinde seçilen tüm rolleri kullanıcıyla ilişkilendirerek atama işlemini sonlandıracağız.

    public class RoleController : Controller
    {
        readonly RoleManager<AppRole> _roleManager;
        readonly UserManager<AppUser> _userManager;
        public RoleController(RoleManager<AppRole> roleManager, UserManager<AppUser> userManager)
        {
            _roleManager = roleManager;
            _userManager = userManager;
        }
        public async Task<IActionResult> RoleAssign(string id)
        {
            AppUser user = await _userManager.FindByIdAsync(id);
            List<AppRole> allRoles = _roleManager.Roles.ToList();
            List<string> userRoles = await _userManager.GetRolesAsync(user) as List<string>;
            List<RoleAssignViewModel> assignRoles = new List<RoleAssignViewModel>();
            allRoles.ForEach(role => assignRoles.Add(new RoleAssignViewModel
            {
                HasAssign = userRoles.Contains(role.Name),
                RoleId = role.Id,
                RoleName = role.Name
            }));

            return View(assignRoles);
        }
        [HttpPost]
        public async Task<ActionResult> RoleAssign(List<RoleAssignViewModel> modelList, string id)
        {
            AppUser user = await _userManager.FindByIdAsync(id);
            foreach (RoleAssignViewModel role in modelList)
            {
                if (role.HasAssign)
                    await _userManager.AddToRoleAsync(user, role.RoleName);
                else
                    await _userManager.RemoveFromRoleAsync(user, role.RoleName);
            }
            return RedirectToAction("Index", "User");
        }
    .
    .
    .
    //diğer actionlar
    .
    .
    .
    }

Yukarıdaki kod bloğunu incelerseniz eğer; 13. satırda uygulamadaki tüm rolleri, 14. satırda ise o an yetki atanacak olan kullanıcının mevcut tüm rollerini elde edip ardından bu bilgileri bir adım önce oluşturduğumuz “RoleAssignViewModel” isimli viewmodel nesnelerine atayarak view’e gönderiyoruz. Kullanıcıya dair view’de yapılan seçim neticesinde eklenen roller 32. satırda olduğu gibi “AddToRoleAsync” metodu ile kullanıcıyla ilişkilendiriliyor yahut alınan yetkiler ise 34. satırda “RemoveFromRoleAsync” metoduyla kullanıcıdan siliniyor. İlgili view kaynağınıda görmek isterseniz aşağıdaki kod bloğunu inceleyebilirsiniz.

@model List<AspNetCoreIdentityExample.Models.ViewModels.RoleAssignViewModel>
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
<h1>Role Assign</h1>
<form asp-action="RoleAssign" asp-controller="Role">
    <table class="table">
        <thead>
            <tr>
                <th>
                </th>
                <th>
                    Role Name
                </th>
            </tr>
        </thead>
        <tbody>
            @for (int i = 0; i < Model.Count; i++)
            {
                <tr>
                    <td><input type="checkbox" asp-for="@Model[i].HasAssign" /> </td>
                    <td>
                        @Model[i].RoleName
                        <input type="hidden" asp-for="@Model[i].RoleId" />
                        <input type="hidden" asp-for="@Model[i].RoleName" />
                    </td>
                </tr>
            }
            <tr>
                <td colspan="2">
                    <button>Rol Ata</button>
                </td>
            </tr>
        </tbody>
    </table>

</form>

Asp.NET Core Identity - RoleManager Sınıfı İle Rol Yönetimi - XIV

Bu noktadan itibaren bir sonraki içeriğimizde sayfa yetkilendirme(authorization) işlemini ele alacağız.

O halde şimdilik görüşmek üzere diyelim…

İlgilenenlerin faydalanması dileğiyle…
İyi çalışmalar…

Not : Örnek projeyi indirmek için buraya tıklayınız.

Bunlar da hoşunuza gidebilir...

27 Cevaplar

  1. Rafet dedi ki:

    Öncelikle Paylaşımınız için teşekürler
    rolleri listelemek istediğimde bu hatayı veriyor sebebi ne olabilir

    var role = roleManager.Roles.ToList();

    InvalidOperationException: ViewDataDictionary içine aktarılan model öğesi ‘System.Collections.Generic.List`1 [Pro.Eticaret.Identity.AppIdentityRole]’ türündedir, ancak bu ViewDataDictionary örneği ‘System.Collections.Generic türünde bir model öğesi gerektirir. List`1

    • Gençay dedi ki:

      Merhaba,

      Bu hatanın maviyle çizdiğim kısmındaki generic türü sanırım yorumda silinmiş. Tekrar belirtebilir misiniz?
      InvalidOperationException: ViewDataDictionary içine aktarılan model öğesi ‘System.Collections.Generic.List`1 [Pro.Eticaret.Identity.AppIdentityRole]’ türündedir, ancak bu ViewDataDictionary örneği ‘System.Collections.Generic türünde bir model öğesi gerektirir. List`1

  2. seçkin dedi ki:

    Gencay Hocam Selamlar,
    Identity sisteminden kullanıcı sildiğimde, bağlı olarak atandığı rolleride silinsin, ya da aspnetuserroles tablosunu update etmek, istiyorum ama sürekli hata alıyorum.
    _userManager.RemoveFromRoleAsync(user,role) bu arkadaş patlatıyor. MySQL Dublicate Entry hatası alıyorum. Bir türlü çıkamadım işin içinden. .net core 3.1 kullanıyorum.

  3. Cihan dedi ki:

    @model AspNetAuth.Models.Authentication.AppRole
    @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

    Roller

    Bu AppRole görmüyor nedenini anlamadım

  4. public void ConfigureServices(IServiceCollection services)
    {
        services.AddIdentity<AppUser, AppRole>(_ =>
        {
            .
            .
            .
        }
    }
    
    • Kamil Yasin ABLAY dedi ki:

      Hocam burası çok tanımsız kalmış içine basit olarak ne yazmalıyız.

      • Gençay dedi ki:

        Sadece AppRole sınıfının nerede ve ne şekilde tanımlanması gerektiğine dair prototip paylaşılmış. İçerisine ne yazacağınızı yazı dizisini baştan sona okursanız anlatmış bulunmaktayım.

        Kolay gelsin.

  5. yasin dedi ki:

    An unhandled exception occurred while processing the request.
    ArgumentNullException: Value cannot be null. (Parameter ‘user’)
    Microsoft.AspNetCore.Identity.UserManager.GetRolesAsync(TUser user)

    Stack Query Cookies Headers Routing
    ArgumentNullException: Value cannot be null. (Parameter ‘user’)
    Microsoft.AspNetCore.Identity.UserManager.GetRolesAsync(TUser user)
    yasin.Controllers.RoleController.RoleAssign(string id) in RoleController.cs
    +
    List userRoles = await _userManager.GetRolesAsync(user) as List;

    Merhaba rol tanımlayacağım zaman bu hatayı veriyor sorunu nasıl çözebilirim

  6. yasin dedi ki:

    hocam orayı hallettim
    ama şimdi başka bir sorun var
    burada indexe basınca login e gidiyor neden acaba

                <a>Index</a> |
                <a>Signin</a> |
                @if (User.Identity.IsAuthenticated)
                {
                    <a>Roles</a> @: |
                    <a>Birimler</a> @: |
                    <a>Personeller</a> @: |
    
                    <a>Profile</a> @: |
    
                    <a>Logout</a>
                }
                else
                {
                    <a>Login</a> @: |
    
  7. yasin dedi ki:
                @for (int i = 0; i < Model.Count; i++)
                {
                    
                         
                        
                            @Model[i].RoleName
                            
                            
                        
                    
                }
                
                    
                      
                        Rol Ata
    

    Buradan basıncada Logine gönderiyor sanki kişi login olmamış gibi ama login olduğuna göre Roles Profil sayfa linkleri aktif oluyor

  8. yasin dedi ki:

    hocam sizin gmailinize bir video gönderdim bakabilir misiniz?

  9. yasin dedi ki:

    [Authorize()] burayı silince sayfaya giriyor yazmışsınız zaten ama bu varsa ve login olmuşsanız
    zaten girmeniz gerekli sayfaya değil mi
    peki login olduğumuzu nasıl anlayacağız Profile Ve Roles linkleri çıkıyorsa login olmuş olmuyor muyuz? bunlar çıktığı halde neden Index e girmiyor startupta başka bir olay mı var

  10. yasin dedi ki:

    sartupta cookie ile alakalıymış bazı yerleri düzelttim sorun kalmadı yanlız burada böyle bir problem var diyelimki rol sadece admin verebiliyorsa admine yetkiyi kim verecek yani önceden tanımlanmış bir kullanıcı olması gerekiyor varsayılan olarak o giriş yapıp gerekli düzenlemeleri yapması gerekir startupta ve appsetttingste bazı ayarların yapılması gerektiğini düşünüyorum
    ben bu arada lise mezunuyum hobi olarak yapıyorum bunları yanlışım varsada affola

    • Gençay dedi ki:

      Gayet doğru düşünüyorsunuz. O yüzden genellikle uygulamalarda ‘admin’ default olarak öntanımlı bir şekilde belirlenir.

  11. yasin dedi ki:
    app.UseEndpoints(endpoints =>
                {
                    endpoints.MapControllerRoute(
                        name: "default",
                        pattern: "{controller=Default}/{action=Index}/{id?}");
                    endpoints.MapRazorPages();
                });
    
                new[] {
                    new Rol { Name = "Administrators", GörünenAd = "Yöneticiler" },
                    new Rol { Name = "Members", GörünenAd = "Üyeler"  },
                }
                .ToList()
                .ForEach(_ =>
                {
                    var result = roleManager.RoleExistsAsync(_.Name).Result;
                    if (!result)
                        roleManager.CreateAsync(_).Wait();
                });
    
                var varsayılanAdmin = new Kullanıcı
                {
                    UserName = Configuration.GetValue("Security:defaultAdminUsername"),
                    AdSoyad = Configuration.GetValue("Security:defaultAdminName"),
                };
    
                var result = userManager.CreateAsync(varsayılanAdmin, Configuration.GetValue("Security:defaultAdminPassword")).Result;
                if (result.Succeeded)
                    userManager.AddToRoleAsync(varsayılanAdmin, "Administrators").Wait();
            }
    aspsettingte
     "Security": {
        "defaultAdminUsername": "admin",
        "defaultAdminName": "Varsayılan Admin",
        "defaultAdminPassword": "12abCD*987"
      }
    
  12. yasin dedi ki:

    default kullanıcı oluşturlmuş hali starup cs de

  13. ramazan dedi ki:

    merhaba hocam,
    bu yazınızı ve sonraki yazınızı birkaç kez okudum . şöyle bir şeyi nasıl yaparız.
    Roles = “tor,Editor,Moderator,Administrator” bu rollere sahip kişilerin kullanıcı girişi yapmadan yani login olmadan bazı sayfaları görmesini bazı sayfalarını görmemesini nasıl sağlayabiliriz.
    Örneğin tor yetkisi sadace page1 görsün ama login olmasına gerek olmadan. yada Administrator page3 ile page 4 görsün ama login olmasına gerek kalmadan

  1. 25 Eylül 2019

    […] Asp.NET Core Identity – RoleManager Sınıfı İle Rol Yönetimi – XIV […]

  2. 02 Ekim 2019

    […] önceki RoleManager Sınıfı İle Rol Yönetimi başlıklı makalemizde uygulama bazlı rol yönetimini incelemiş bulunmaktayız. Bu […]

  3. 08 Kasım 2019

    […] Based Authorization, yetkilendirilmiş sayfalarda belirlenmiş rollerin dışında, türlü politikalar belirlememizi sağlayan ve kimlik doğrulama sürecinde bu […]

Bir cevap yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

*