.Net Core 3.1 Üzerinde Controller ve Action Bazlı Kullanıcı Yetkileri

Selamlar,

https://youtu.be/kt7t6ufM7jY

Bu makalede .Net 3.1 üzerinde çalışan bir WebApi servisinde, userlara her bir sayfa için ve her sayfaya ait methodlar için verilecek yetkileri, detaylıca inceleyeceğiz. Bu makalede Database olarak “Microsoft Sql Server 2014” kullanılmıştır. Eğer makinanızda Northwind database yok ise, bu link’deki script’i Sql Management Studio’da çalıştırarak, indirebilirsiniz. Daha sonra User, RoleGroups, Roles ve UserRoles tablolarını, yine aşağıdaki scripti çalıştırarak, dataları ile birlikte oluşturabilirsiniz. Amaç Türkiyedeki gerçek hayat senaryolarını size en doğru şekilde yansıtabilmektir :) Normalde, makaleler CodeFirst yazarak işlemlerine devam etmektedir. Ama gerçek hayatta işler biraz farklı olabilir. Siz bir firmaya gittinizde, Database zaten ordadır. Bussines DB üzerinde şekillendirilerek çoktaaan çıkarılmıştır :) Bu nedenle bu makalede, ben pek haz etmesem de, DB First kullanılmıştır. Ayrıca katmanlı mimari ve bir projede olması gereken Business Logic kavramlarına, biraz olsun girilmiştir.

http://www.borakasmer.com/projects/Users&RolesScript.txt

Database

Users: Kullanıcı bilgilerinin doldurulduğu tablodur.

RoleGroups: Aslında her bir sayfaya, yani Controller’a karşılık gelen yetki tablosudur.

Roles: Sayfa üzerindeki, her bir Action’a karşılık gelen yetki tablosudur. Burada dikkat edilmesi gereken bir husus da, RoleID alanının “bigint” olmasıdır. Bu kısım makalenin devamında detaylıca anlatılacaktır.

UserRoles: Her bir kullanıcının, Controller ve Action bazında yetkisi, bu tablo üzerinde tanımlanır. Burada da Roles alanı, yukarıda bahsedilen Role tablosundaki RoleID gibi, “bigint“‘dir.

 

.Net Core Proje Oluşturma

Şimdi gelin Visual Studio2019 ile WebApi .Net Core projesini, aşağıda görüldüğü gibi oluşturalım.

Proje Tipi olarak, API seçilir.

Properties/launchSettings.json: Aşağıdaki gibi değiştirilir. iisSettings‘de sslPort‘u 0 yapılarak projenin “http“‘den çalışması sağlanmıştır. Ayrıca, profiles sekmesinden IIS Express ==> launchURL :”api/person” olarak değiştirilir. Son olarak istenir ise uygulama, “IIS Express” yerine “UserRoles” profilinden de çalıştırılabilir.

Ayrıca WeatherForecastController ==> PersonController olarak değiştirilir. WeatherForecastController, proje oluşturulduğunda default olarak gelen servisdir.

PersonController: Default olarak gelen Controller, aşağıdaki gibi değiştirilir. Bu sayfa, tamamen test amaçlı olduğu gibi bırakılmıştır. Makalenin devamında, ihtiyaca göre değiştirilecektir.

Uygulama IIS Express profili ile çalıştırıldığında, aşağıdaki gibi bir ekran ile karşılaşılır.

Database First DB Entity Oluşturma

Şimdi DB adında yeni bir Library Projesi oluşturalım. Amaç Northwind database’i ile alakalı Context’i ve buna bağlı Entityleri oluşturmaktır. Aşağıda görüldüğü gibi, DB adında “Class Library (.Net Core)” projesi oluşturulmuştur.

Entities” adında yeni bir folder, aşağıdaki gibi oluşturulur.

Öncelikle Nuget’den aşağıdaki kütüphaneler indirilir. Makale yazıldığı an itibari ile, v3.1.1 versiyonları mevcuttur.

Eğer makinanızda yok ise, EF Core Tools’un yüklenmesi gerekmektedir. Aşağıda görüldüğü gibi, test makinasında eski bir versiyonu bulunmakta idi.

EF Core Tools’nun güncellenmesi için, önce var olan sürümün, aşağıdaki komut ile silinmesi gerekmektedir.

Daha sonra aşağıdaki komut ile makalenin yazıldığı an itibari ile, “3.1.0” versiyonunu yüklenir. “3.1.1” versiyonu ile uyuşmazlık olduğu için, bu versiyon özellikle yüklenmiştir!

Command prompt’a geçip, yukarıda görüldüğü gibi DB folderının altına gelinir. Ve aşağıdaki komut ile localde çalışan SqlDB’den Northwind database’ine bağlanılıp, tüm entityler ve NorthwindContex’i, ilgili folder altında oluşturulur. Bu işleme, “Database First” denilmektedir. Var olan bir DB olduğu için, bu yöntem tercih edilmiştir.

Aşağıda, otomatik oluşan Entityler, ve Northwind DBContext’i gözükmektedir.

.Net Core’da, Dependency Injection ile ilgili DB Context’in ayağa kaldırılması için, Startup.cs’de aşağıdaki kodun tanımlanması gerekmektedir.

Startup.cs:

Ayrıca ConnectionString için appsettings.json, aşağıdaki gibi değiştirilir.

appsettings.json: Northwind database’ine bağlanmak için, “ConnectionStrings” tanımlaması aşağıdaki gibi eklenmiştir.

Repository Oluşturma

Şimdi sıra geldi, yetki amaçlı Roles servisinin yazılmasına. Her bir servis, güvenlik nedeni ile doğrudan DBContext’e erişmemeli, araya Repository katmanı ile data etkileşimine girmelidir. O zaman gelin, Repository adında, yeni bir Class Library projesi oluşturalım.

IRepository: Repository katmanının türeyeceği Interfacedir. Aşağıda görüldüğü gibi, bir servis içinde Entity ile yapılabilecek genel işlemler, global bir sınıf altında toplanmıştır.

Repository: Burada esas amaç, hangi Entity alınır ise alınsın, hepsinde ortak geçerli olan DB işlemleri için tek bir kodun yazılması, ve kod tekrarından kaçınılmasıdır.

  • Table” :  DBContext’deki, Entity’ye karşılık gelmektedir.
  • Entities” : NorthwindContext’in kendisidir.

Kişilerin yetkisini, yani alınan RoleModel’i, aşağıdaki gibi oluşturalım.

RoleModel: Aşağıda görüldüğü gibi, bir User’ın yetkileri UserIDRoleGroupID(Controller) yani sayfa ve RoleID(Action) yani method bazında tutulmuştur.

NOT: Normalde her model, bir BaseModel’den türetilmelidir. Burada, konu dışı olduğu için çıkarılmıştır.

Startup.cs: Yine repostroy katmanının Dependency Injection ile ayağa kaldırılması için, Startup.cs’de aşağıdaki kodun tanımlanması gerekmektedir. “IRepository” AddScoped ile eklenmiştir.

Servis Oluşturma

IServiceResponse : Her servisin döneceği, ortak modelin interface’idir.

ServiceResponse : Her servisin döneceği, ortak bir model olmalıdır. Bu örnekte de bu model, ServiceResponse sınıfıdır.

  • “List” : Kayıt kümesi dönüleceği zaman kullanılır. Örneğin bir sayfa üzerindeki tüm yetkiler liste şeklinde bu property’e atanabilir.
  • “Entity” : Tek bir kaydın dönülmesi durumunda, kullanılır.
  • “Count” : Dönen toplam kayıt sayısıdır.
  • “IsSuccessful” : İşlemin başarılma durumunu gösterir.

IRoleService: User yetkisinin, sayfa bazında hangi methodlar için geçerli olduğunu ve method bazında yetkili olup olmadığını, aşağıdaki Inteface’de görülen methodlar ile kontrol edilir.

*Bitwise Öteleme

Şimdi tam burada bir ara verip, her bir user’a verilen yetki konusunu konuşalım. Bu makalede, standart yöntemlerin çok dışında bir yetkilendirme metodolojisi kullanılmıştır. Amaç, size tamamen başka bir bakış açısı katmaktır. Okullarda anlatılan mühendislik konularının, gerçek hayatta nasıl kullanılabileceğini gösteren en somut örneklerinden biri de, bu konudur. Biri, okul önemli dediğinde çıkarıp ona sunabileceğiniz makalelerden biri de bu diyebilirim. Dikkatinizi çekildi isem :), şimdi gelelim işin özüne.

Yukarıdaki sorgu sonucuna bakılığında, RoleGroup yani sayfa başına yetki için, sadece bir sayı yazıldığını “7” görebilirsiniz. Bu sayı, sayfa üzerinde user’a verilen tüm yetkilere karşılık gelmektedir. Peki nasıl ?

Sayfalar üzerindeki tüm yetkiler sorgu olarak çekildiğinde, yukarıdaki gibi bir sonuç ile karşılaşılır. Sayfa bazında tüm yetkiler yani RoleID, 2‘nin katları şekilde artmaktadır. En fazla 63 eleman bu şekilde tanımlanabilmektedir. Çünkü, C# dilinde Maximum sayı büyüklüğü 2^63’e kadar yani, “double” tipine karşılık gelmektedir. Bu tipin Sql’deki karşılığı, “bigint“‘dir. Sanırım makalenin başında tabloları tanımlarken, RoleID’nin tipini neden bigint olarak atadığımızı, artık anlamışsınızdır :)

Bitwise ötelemede istenen yetkilere karşılık gelen RoleID toplanır, ve toplamına karşılık gelen sonuç User’a atanır. Örneğin, yukarıdaki sorgudan yola çıkar isek:

Örnek: Sayfa 2, yani GroupID 2’için ==> “GetCustomer() => 1 ve GetCustomerList() => 4 yetkileri bir user’a verilmek istenir ise, toplamı olan “5” sayısı, Roles alanına atanır. 

O zaman “select * from [dbo].[UserRoles]” sorgusunda, UserID = 1 için ==> Roles 7 değeri alınarak, ilgili client’a, Sayfa 2 için tüm yetkilerin verilmesi sağlanmıştır. 1+2+4 = 7 (GetCustomer + GetCustomerById + GetCustomerList)

Peki aranan yetkinin, ilgili kayıt kümesinde olup olmadığına nasıl bakılır?

Örneğin, GetCustomerList() yetkisinin RoleID’si 4‘dür. UserID = 1 için tüm yetkilerin değeri 7‘dir. O zaman gelin 4 yetkisini, 7’nin içinde var mı diye bakalım. Aşağıdaki koşul, “true” değerini dönecektir. Bitwise öteleme işte tam da budur. Esas amca, User’ın her bir yetkisi için yeni bir satırın oluşmasını engellemek ve data kalabalığına son vermektir. Hatta her sayfa, yani Controller için çoklu yetki verilmese idi, farklı bir tablo yapılmasına gerek kalmayacak, User tablosuna tek bir kolonun açılması yeterli olacaktı.

if(4 == (7 & 4)) ==> true

Bitwise Öteleme hakkında, daha detaylı bilgiye buradan erişebilirsiniz. https://medium.com/@vbtbilgi/c-sql-iterations-382b46df1d39

Servisler

RoleService: Sayfaya girmek isteyen bir kişinin ya da sayfada herhangi bir yere tıklayan kişinin, yetkisinin olup olmadığına bakıldığı yerdir.

  • “_userRolesRepository” : User’a ait rollerin, tutulduğu tablodur. UserRole tablosuna karşılık gelir.
  • “_rolesRepository” : Sayfalara göre guruplanmış, tüm rollerin listesinin tutulduğu tablodur. Roles tablosuna karşılık gelir.
  • GetRoleById()” :  User’ın, ilgili Action’a yetkisinin olup olmadığına “Bitwise Öteleme” ile bakıldığı yerdir.
    • “response” : Her servisin döndüğü ortak model olan, ServiceResponse modelidir.
    • “model” : User’ın yetkilerinin tutulduğu, RoleModel’dir.
    • “var userRole = _userRolesRepository.Table.Include(r => r.RoleGroup).FirstOrDefault(ur => ur.UserId == userId && ur.RoleGroupId == roleGroupID)”:  İlgili user(UserId) ve Sayfaya(RoleGroupId)’ye göre, client’ın o sayfa üzerindeki yetkilerinin toplamı çekilir.
    • “if (roleID == (userRole.Roles & roleID))” : O sayfa için gerekli olan yetki(roleID), bitwise ile User Rollerinde var mı, diye bakılır. Kısaca User, ilgili sayfaya girebilir mi diye kontrol edilir.
    • “var role = _rolesRepository.Table.Where(r => r.RoleId == roleID).FirstOrDefault()” : Aranan role’ün kaydı, Roles tablosundan çekilir.
    • “model = new RoleModel() { Id = role.Id, RoleName = role.RoleName, RoleGroupID = (int)userRole.RoleGroupId, RoleID = roleID, UserID = userId, GroupName = userRole.RoleGroup.GroupName }” : Methodun dönmesi gereken RoleModel, aranan Role’e göre doldurulur.
    • ” response.Entity = model”: Her servisin döndüğü Response Model’den, tekil kayıt alan Entity, RoleModel ile doldurularak geri dönülür.
  • “GetRoleListByGroupId()”: Bu methodda amaç, User’ın o sayfaya ait tüm yetkilerinin çekilmesidir. Herbir yetki, farklı bir satır olarak geri dönülecektir. Böylece, sayfa daha ilk yüklenirken, kullanıcı sadece yetkili olduğu alanları görebilecektir.
    • “var response = new ServiceResponse<RoleModel>()” : Her servisin döndüğü, ServiceResponse modeli oluşturulur.
    • “List<RoleModel> model = new List<RoleModel>()” : Bu sefer servisden geri dönülecek, ServiceResponseModel’inin List property’si, List of RoleModel ile doldurulacaktır.
    • “var userRole = _userRolesRepository.Table.FirstOrDefault(ur => ur.UserId == userId && ur.RoleGroupId == roleGroupID)” : User’ın o sayfa için olan tüm yetkileri, tek bir değer olarak alınır.
    • “var allRoles = _rolesRepository.Table.Include(r => r.Group).Where(r => r.GroupId == roleGroupID).ToList()” : İlgili sayfaya ait tüm roller, kontrol edilmek amacı ile çekilir.
    • foreach (var role in allRoles)” : Çekilen tüm roller, tek teke gezilir.
    •  if (role.RoleId == (userRole.Roles & role.RoleId))” : Sıra ile bakılan herbir role, User’ın rollerinden biri mi bitwise ile kontrol edilir.
    • “model.Add(new RoleModel() { Id = role.Id, RoleName = role.RoleName, RoleGroupID = (int)role.GroupId, RoleID = (int)role.RoleId, UserID = userId, GroupName = role.Group.GroupName })”: Kontrol edilen yetki, User’ın role’ü ise, yeni bir RoleModel olarak model listesine eklenir.
    • ” response.List = model”: Dolan List of RoleModel (List<RoleModel>), bu sefer Response Model’in List property’sine atanır.
    • “return response” : Kullanıcının sayfa üzerindeki tüm yetkileri, ServiceResponse olarak geri dönülür.

RoleService:

Startup.cs: YazılanRoleService, projeye yine “AddTransient<IRoleService, RoleService>” olarak Startup.cs altında tanımlanarak, aşağıdaki gibi eklenmesi gerekmektedir.

Actionlar

Şimdi sıra geldi, PersonController’da Userlar için yetki tanımlanan Actionların oluşturulmasına:

Sql üzerinde aşağıdaki sorgular yapılınca, Customer için yazılacak methodların  listesi, yetkilerden çekilir. Neden yetkilerden, yazılacak methodlara gittiği mi soracak olursanız, gerçek hayatta bilginin ne kadar acayip yerlerden :) gelebileceğine bir örnek vermek için derim.

Öncelikle gelin, geri dönülecek PersonModel’i oluşturalım: Model folder’ı altında, aşağıdaki sınıf oluşturulur.

  • Date : Sınava giriş tarihi.
  • Age : Yaşı
  • Score : 100’lük sayı değeri ile gelen sonuç, 5’lik sınav sonucuna dönüştürülür.
  • Name: Katılımcı adı.

Örnek çıktı:

Aşağıda Names adında test amaçlı, Mocap isim datası üretilmiştir.

Sayfaya ilk gelinildiğinde, GetCustomer() methodu çalıştırılır.

  • “var rng = new Random()” : Belirlenen aralıkta, rastgele değer üretmek için kullanılır.
  • “return Enumerable.Range(1, 5).Select(index => new PersonModel” : 5 adet PersonModel, üretilir.
    • “Date = DateTime.Now.AddDays(index).ToShortDateString()” : Sıra ile, günümüzden birer gün olarak artan tarih girilir.
    • “Age = rng.Next(18, 56)” : 18- 56 arası rastgele bir yaş üretilir.
    • “Score = rng.Next(1, 101)” : Rastgele 1 – 100 arası sınav sonucu üretilir.
    • “Name = Names[rng.Next(0, 10)]” : Dummy olarak üretilen 9 isimden 1 tanesi, rastgele seçilir.
  • “.ToArray()” En son 5 elemanlı PersonModel, dizi olarak geri dönülür.

GetCustomerById : Bu method da GetCustomer()’ın aynısıdır. Terk farkı, 1 tek kişinin kaydı geri dönülür.

  • “Name = Names.Any(n => n == personID) == false ? “Bora” : personID” : Kayıdı alınmak istenen kişinin adı, mocap list’de yok ise, default olarak “Bora” dönülür.

GetCustomerList : Bu method da, GetCustomer() methodunun aynısıdır. Sadece listelenecek kayıt sayısı, parametre olarak alınmıştır.

Enumlar

Şimdi sıra geldi, yetkileri belirlemeye:

Öncelikle Solution’da “Class Library” Core adında yeni Proje oluşturalım. Ve ilk sınıfımız Enumlar olacaktır. Solution’ın son görünümü, aşağıdaki gibidir.

Core/Enum.cs: Amaç, ilgili methodlar için yetki sorgularken, ne olduğu anlaşılmayan sayılar yerine Enumların kullanılmasıdır. Yetkiler Gurup yani Controller ve Page yani Action şeklinde verildiği için, Enum tanımlamaları da Controller ve Action bazında yapılmıştır.

Custom Action Filter Oluşturma

Şimdi sıra geldi bir işaretleyici yapmaya. Yani ilgili Action’ı işaretlemek için, “Custom Action Filter” yapmaya. Bu şekilde belli bir yetki ile girilmesi gereken sınıfları belirleyip, yetki kontrolü yapacağız. Filter’a atanacak parametreler, yukarıdaki Enum değerler olacaktır.

Core/RoleAttribute: Aşağıda görüldüğü gibi bir RoleAttribute’ü, Core projesi içinde oluşturulmuştur.

2 parametresi vardır. 1. roleGroupID, 2. roleID. Amaç, client’ın ilgili Controller’daki Action’a, yetkisinin olup olmadığının bakılmasıdır. Dikkat edilir ise, roleID => Int64‘dür. Çünkü yetki ID’leri 2’nin katı şeklinde 2^63’e kadar alınabilmektedir.

Sınırlama Getirme

Şimdi sıra geldi PersonController’dan bir Action’a, sınırlama getirmeye:

[RoleAttribute((int)RoleGroup.Customer, (Int64)CustomerRoles.GetCustomerList)]

Person/GetCustomerList() : Aşağıda görüldüğü gibi, ilgili GetCustomerList() Action’ına [RoleAttribute]’ü eklenmiştir. Parametre olarak RoleGroup.Customer cotroller’ının, CustomerRoles.GetCustomerList action’ı verilmiştir. Gönderilen parametrelere göre ilgili Action’ın RoleID‘değeri, User’ın o Controller için yetkiler toplamı olan, “Roles” değeri içinde bitwise olarak aranır.

*Son olarak makalenin devamında yazılacak olan Custom Filter’ın da, “[ServiceFilter(typeof(PermissionFilter))]” olarak tanımlaması gerekmektedir. Böylece ilgili methodun çağrılmadan önce, “Permission Filter“‘a girmesi sağlanmıştır.

Custom Filter

Şimdi sıra geldi Custom bir Filter yapmaya.

PermissionFilter: Amaç, daha webersivisine gelmeden önce, araya girip “OnActionExecuting()” methodunda, gelen User’ın ilgili Action için yetkisinin olup olmadığının kontrol edilmesidir. Tüm Filterlar, “IActionFilter”‘dan türetilirler ve 2 methodun inherit edilmesi gerekmektedir. OnActionExecuting() ve OnActionExecuted().

  • public bool HasRoleAttribute(FilterContext context)” : Gidilmek istenen Action’ın başında, “RoleAttribute” ile işaretlendi mi diye bakılır. Ancak bu attribute ile işaretlenen Actionlar için, Role kontrolü yapılacaktır. Diğer actionlar için kısıtlama yoktur.
  • “public void OnActionExecuting(ActionExecutingContext context)” : Webservisine gitmeden önce, girilen methoddur. Esas yetki kontrolü burada yapılır.
  • “int.TryParse(context.HttpContext.Request.Headers[“UserId”].FirstOrDefault(), out var userId)” : Action’a erişmek isteyen client’ın UserID’si, header’dan alınır.
  • *“var arguments = ((ControllerActionDescriptor)context.ActionDescriptor).MethodInfo.CustomAttributes.FirstOrDefault(fd => fd.AttributeType == typeof(RoleAttribute)).ConstructorArguments”: Erişilmek istenen methodun tepesinde tanımlanan [RoleAttribute]’a atanan parametreler, burada yakalanır.
  • “int roleGroupID = (int)arguments[0].Value; Int64 roleID = (Int64)arguments[1].Value” : Yakalanan “RoleGroupID” ve “RoleID“, değişkenlere atanır.
  • “RoleModel role = _roleService.GetRoleById(userId, roleGroupID, roleID).Entity” : Client’ın, ilgili method için yetkisinin olup olmadığına burada bakılır. Kısacası “UserRoles” tablosundan, UserID ve RoleGroupID parametrelerine göre tüm yetkilerin döndüğü Roles değeri alınır. Daha sonra RoleName ve RoleGroupID’ye göre, “Roles” tablosundan RoleID değeri bulunur. Ve son olarak bulunan bu RoleID, yetkilerin döndüğü Roles değeri içinde, bitwise ile aranır. Eğer herhangi bir kayıt bulunur ise, geriye RoleModel dönülür.
  • “if (role.Id == 0)” : Eğer herhangi bir kayıt bulunamaz ise, Forbidden 403 cevabı geri dönülür.
  • “context.Result = new ObjectResult(context.ModelState) { Value = “You are not authorized for this page”, StatusCode = Microsoft.AspNetCore.Http.StatusCodes.Status403Forbidden }” : HttpContext’in result’ına, Custom bir ObjectResult dönülür. User’ın bu methoda yetkisinin olmadığı, “Status403Forbidden” StatusCode’u şeklinde bildirilir.

Yukarıda tanımlı PermissionFilter’ın da dependency injection ile ayağa kaldırılabilmesi için, Startup.cs’de aşağıdaki gibi  “AddScoped<PermissionFilter>” şeklinde tanımlanması gerekmektedir.

Kullanım Şekli: “[ServiceFilter(typeof(PermissionFilter))] ” ilgili filter, Action ya da Controller üstüne konarak methoda girmeden önce “HasRoleAttribute” işaretlemesi var ise, yetki kontrolünün yapılması sağlanmıştır.

Startup.cs: Son hali aşağıdaki gibidir.

Kısaca yaptıklarımız bir toparlarsak :

  • Öncelikle DB First mantığı ile, Database, tablolar ve test amaçlı datalar oluşturulmuştur.
  • Daha sonra bir .Net Core projesi oluşturularak ayağa kaldırılmıştır.
  • DB amaçlı, Class Library şeklinde yeni bir proje oluşturulur. EF Core Tools yardımı ile, Database ve Tablolara karşılık gelen DB Context ve Entityler tek bir komut ile yaratılır.
  • Tüm Entityler için geçerli olan bir General Repository katmanı oluşturulur ve tüm DB işlemleri bu katmanda yapılır. Aynı zamanda, DB Context’e direk Servisden erişim güvenlik amacı ile araya bir katman konarak engellenmiş olunur.
  • Bu Repository katmanının kullanıldığı Servis katmanı oluşturulur. İlgili servisde, yetki ile ilgili tüm sorgulamalar yapılır. Tüm yetkiler performans amaçlı, tek bir kolona atanmıştır. Bitwise öteleme ile aranacak yetki, ilgili kolondan denenerek bakılır. Tüm enitityler için servis, tek bir result tipi dönmektedir. Bu da “ServiceResponse” modeldir. Böylece projenin her yerinde, aynı tip model ile çalışılır.
  • Tüm parametrik değerler için yani Controller ve Actionlar için Enum değerler üretilir.
  • Yetkilerin, tanımlanan methodlar veya Controller için bakılması için, ayırt edici “RoleAttribute” oluşturulur. Tüm methodlar için yetkiye, bu işaretleyici yardımı ile bakılır.
  • Custom PermissionFilter : Başına RoleAttribute konan methodların, çalıştırılmadan önce devreye giren kontrol sınıfıdır. Giren User’ın yetkili olup olmadığına burada bakılır.

Geldik bir makalenin daha sonuna. Bu makalede uçtan uca katmanlı bir mimari kullanılarak, yetki kontrolünün method ve client  bazında nasıl yapıldığını hep beraber inceledik. Umarım işinize yarar.

Yeni bir makalede görüşmek üzere, hepinize hoşçakalın.

Source Code: https://github.com/borakasmer/.Net-Core-UserRoles

Herkes Görsün:

Bunlar da hoşunuza gidebilir...

19 Cevaplar

  1. Niyazi dedi ki:

    Emeğinize sağlık hocam teşekkür ederiz

  2. mustafa dedi ki:

    Harika bir makale daha emeğinize sağlık.

  3. Safa dedi ki:

    Emeğimize sağlık hocam. IRepository Scoped ve IRoleService’ Transient olarak tanımlamanızın bir sebebi var mı? İkisi de Singleton problem oluşturacak bir durum var mı?

    • borsoft dedi ki:

      Teşekkürler Safa. Repository katmanı Scoped olarak tanımlanır ise, using{}’li bir kullanım halini almış olur. Bu da yüksek trafikde performans artışına sebebiyet verir. Çünkü sadece kullanıldıkları zaman yaratılıp kaldırılırlar. Yüksek trafikte 20K kişinin siteye gelmesi ile Transient tanımında 20K Repository katmanı, session ayakta olduğu sürece yer kaplayacak ve bu da ciddi bir maliyet doğuracaktır. IRoleService için de yine aynı durum geçerlidir.

  4. Safa Güneş dedi ki:

    Emeğimize sağlık hocam. IRepository Scoped ve IRoleService’ Transient olarak tanımlamanızın bir sebebi var mı? İkisi de Singleton olsa problem oluşturacak bir durum olur mu?

    • borsoft dedi ki:

      Teşekkürler. Repository katmanı Scoped olarak tanımlanır ise, using{}’li bir kullanım halini almış olur. Bu da yüksek trafikde performans artışına sebebiyet verir. Çünkü sadece kullanıldıkları zaman yaratılıp kaldırılırlar. Yüksek trafikte 20K kişinin siteye gelmesi ile Transient tanımında 20K Repository katmanı, session ayakta olduğu sürece yer kaplayacak ve bu da ciddi bir maliyet doğuracaktır. IRoleService için de yine aynı durum geçerlidir.

  5. Yusuf dedi ki:

    Teşekkür ederiz çok güzel bir kaynak olmuş. Favorilere ekliyorum :)

  6. Şakir dedi ki:

    Eline emeğine sağlık hocam. Değişik ve değerli bir bakış açısı için uğraş vermişsin teşekkürler. Ancak anlayamadığım bir konu var. Fazlaca rol olan sistemlerde kontrol nasıl olacak? Belki verdiğim örnek yanlış ama sorumun mantığını anlatmak adına; Diyelim ki rol toplamı 18. Bunun 12+6, 14+4, 10+ 8, 8+6+4 ya da sadece 18 olabilme gibi olasılıkları var. Bu ayrımı nasıl yapıyoruz?

    • borsoft dedi ki:

      Selam Şakir,
      Öncelikle güzel yorumun için teşekkürler. Bitwise öteleme, senin anladığın şekilde çalışmıyor. Şurada detaylıca anlattım. Tek olumsuz durum 2^63 yani 63 item bir grup altında tanımlayabilirsiniz.

      Video’yu izledikten sonra halen aklında soruların olur ise, buradan bana sorabilirsin.

  7. Mustafa dedi ki:

    Merhaba Hocam,

    Makale için teşekkürler, çok güzel bir makale olmuş. Benim tam olarak anlayamadığım konu şu, biz 63 tane yetkiyi(action) toplam bütün controller için mi verebiliyoruz ? Yoksa ben HomeController için 63 tane action tanımlayabilirim. PersonController için de 63 tane ayrı action tanımlayabilir miyim ?

    • borsoft dedi ki:

      Selam Mustafa,

      Öncelikle teşekkürler. Her bir controller için 63 tane yetki verebilirsin.
      Yani HomeController için 63 Action yetkisi, PersonController için 63 Action yetkisi. RoleGroup ==> Controller, Role ==> Action.

      İyi çalışmalar

  8. Caglar dedi ki:

    Teşekkürler. Gerçekten çok büyük bir derdi çözdü. Ayrıca sizin yazıların şöyle bir faydası var . Bir konuyu öğrenirken başka bir konuda nasıl daha iyi yapılacağını gösteriyor. Örn: response meselesinde interface tanımlamak.
    Yalnız protected virtual DbSet Entities => _entities ?? (_entities = _context.Set()); bunun mantığı nedir anlayamadım.
    Elinize sağlık.

  9. Mesut Dede dedi ki:

    Hocam selamlar,

    Öncelikle bu güzel makale için teşekkürler. Emeğinize sağlık.
    Ben ServiceResponse olayı ile ilgili bir soru sormak istiyorum. ServiceResponse içersinde HttpStatus kodlarını da handle etmek gerekmez mi? Mesela IsSuccessful false olan bir operasyon için Http200 dönüyor olması tezat olmaz mı?

    • borsoft dedi ki:

      Selamlar,
      Olur. Zaten status kodlara hep bakmak gerekir.Burdaki IsSuccessfu işleri biraz daha hızlandırmak için konulmuştur..

      İyi çalışmalar.

  10. Mr.Engineer dedi ki:

    Merhaba hocam,
    Emeğinize sağlık hocam. Çok yararlı bir kaynak.
    Bir projede gördüm IActionDescriptorCollectionProvider sınıfını kullanıp, Contolleri otomotik yakalayabilirmiyiz.
    Bununla birlikte veritabanında sadece Controller isimlerini tutup yetkilendirme yapmak istiyorum ama bir kaynak bulamadım. Bi eğitim çekermisiniz. Yada bununla ilgili bir döküman varmıdır.
    iyi çalışmalar dilerim.

Bir cevap yazın

E-posta hesabınız yayımlanmayacak.