ASP.NET Core Identity: Cookie-Based Authentication

asp.net core identity api

ASP.NET Core Identity kullanıcılar üzerinde Authentication ve Authorization işlemlerini yürüten bir üyelik sistemidir. Cookie-Based Authentication ve Token-Based Authentication kimlik doğrulama işlemlerini gerçekleştirebiliriz. Bu yazıda Cookie-Based Authentication implementasyonu yapılacaktır.

Cookie-Based Authentication

Görsel incelendiğinde kullanıcı yetkiye tabi bir sayfaya erişmeye çalıştığında uygulamaya giriş yapmamışsa genel davranış itibariyle giriş sayfasına yönlendirilir. Giriş sayfasında credential bilgilerini sunarak kimlik doğrulamaya çalışır. Bu işlem authentication olarak adlandırılmaktadır. Kullanıcı uygulamaya başarıyla giriş yapmışsa authentication token içeren bir cookie oluşturulur. Kullanıcı bu cookie eşliğinde yetkiye tabi sayfaya izinleri doğrultusunda erişebilir.

Yazı boyunca kullanıcı ve roller oluşturacak, kullanıcıya roller atayacak ve kullanıcıları yetkilendirmeye tabi tutacağız. Mvc türünde bir proje oluşturalım ve Entity Framework Core implementasyonu olan Microsoft.AspNetCore.Identity.EntityFrameworkCore Identity NuGet paketini kuralım.

Kullanıcı, rollerimizi temsil edecek sınıflarımızı oluşturarak başlayalım.

Görüldüğü üzere kullanıcılarımızı IdentityUser<TKey> ve rollerimizi IdentityRole<TKey> sınıfı üzerinden türetiyoruz. İhtiyaçlar doğrultusunda ilave kolonlar eklenmiştir.

IdentityDbContext<TUser, TRole, TKey> sınıfından türeyen DbContext sınıfımızı oluşturduk. Program.cs içerisinde gerekli service ve middleware ayarlarını gerçekleştirelim.

DbContext sınıfımızı AddDbContext methoduyla servis olarak ekliyoruz. AddIdentity methoduyla ilgili kullanıcı ve rolü belirterek yetkilendirme mekanizmasını uygulamaya ekliyoruz. Method içerisinde IdentityOptions parametresiyle kullanıcı ve şifreyle ilgili bir takım ayarlamalar yapılmıştır.

Cookie-Based Authentication kullanacağımız için uygulama cookie bilgisini ConfigureApplicationCookie methoduyla konfigüre ediyoruz. CookieAuthenticationOptions property’lerine göz atalım.

  • LoginPath kullanıcı kimliği doğrulanmadığında yönlendirileceği adrestir.
  • LogoutPath kullanıcı çıkış yaptığında yönlendirileceği adrestir.
  • AccessDeniedPath yetkilendirme başarısız olduğunda yönlendirileceği adrestir.
  • ExpireTimeSpan authentication ticket bilgisinin cookie üzerinde hangi zamana kadar saklanacağını belirler ve varsayılan olarak 14 gündür.
  • SlidingExpiration belirtilen sürenin yarısına gelindiğinde sürenin yenilenip yenilenmeyeceğini belirler.
  • Cookie
    • Name cookie ismidir, varsayılan olarak AspNetCore.Cookies değerini kullanır.
    • HttpOnly cookie bilgisinin client-side script tarafından erişilebilirliğini ayarlar.
    • SameSite cookie bilgisinin farklı siteler tarafından erişilebilirliğini ayarlar. Strict ile cookie farklı site isteklerinde taşınmaz. Lax ile bu bilgi taşınır ve None ile bir kısıtlamaya tabi olmaz.
    • SecurePolicy cookie bilgisinin secure bilgisi ayarlanır.

Kullanıcı İşlemleri

Kullanıcı sorumluluklarından sorumlu olacak Controller sınıfını oluşturup kullanıcı kayıt işlemini gerçekleştirelim.

Kayıt işlemini yapacağımız view’ımızı oluşturalım.

Sayfanın post edileceği ilgili Action methodumuzu yazalım.

ViewModel ile gelen bilgiler doğrultusunda CreateAsync methoduyla bir kullanıcı oluşturulup giriş sayfasına yönlendiriliyor. Bu method bize IdentityResult tipinde bir nesne dönmektedir. Bir hata alınmışsa ilgili hatalar ModelState‘e eklenerek ViewModel ile geri gönderiliyor. İlgili hatalara Errors property’sinden erişilmektedir.

Kullanıcı oluşturabildiğimize göre artık kullanıcımızla giriş yapabiliriz.

Action methoduna karşılık düşen view’ı oluşturalım. Action methodumuza bakarsak ReturnUrl adında bir parametre almaktadır. Kullanıcı kimliğini doğrulamadan yetkilendirmeye tabi bir sayfaya erişmeye çalıştığında sayfa adresi query string‘e returnUrl key’iyle eklenerek belirtilen giriş sayfasına yönlendirilmektedir.

Sayfanın post edileceği ilgili Action methodumuzu yazalım.

Kullanıcılarımızı e-posta adresleriyle giriş yaptıracağımız için FindByEmailAsync methoduyla kullanıcımızı elde ediyoruz. Önceki oturumlardan kalma olası cookie bilgilerini temizlemek için SignInManager<TUser> sınıfının SignOutAsync methodunu kullanıyoruz. Sonrasındaysa PasswordSignInAsync methoduyla kullanıcı ve girilen şifreyle kullanıcı giriş yaptırılıyor. Giriş işlemi başarılıysa ResetAccessFailedCountAsync ve SetLockoutEndDateAsync methodlarıyla kullanıcının ilgili lockout alanları sıfırlanmakta ve ilgili sayfaya yönlendirilmektedir. Hesap kilitlenmişse kalan süreyle ilgili hata mesajı GetLockoutEndDateAsync methoduyla ModelState‘e eklenmektedir. Bunlar dışında bir hata alınmışsa hatalar ModelState‘e eklenerek ViewModel ile kullanıcıya geri dönülmektedir.

Kullanıcılarımız giriş yapabildiğine göre artık kullanıcılarımızı çıkış yaptırabiliriz.

Çıkış işlemini sağlayacak Action methodumuzu yazalım.

Kullanıcılar ilgili linke tıkladığında çıkış yaparak asp-route-returnUrl tag helper sayesinde belirtilen adrese yönlendirilecektir.

Yetkilendirme İşlemleri

Kullanıcılarla ilgili işlemleri tamamlamış bulunmaktayız. Artık kullanıcılarımızı bir takım yetkilendirmelere tabi tutabiliriz. Yetkilendirme işlemlerini [Authorize] attribute’ü kullanarak gerçekleştirmekteyiz. Authorize attribute’ü içerisinde Roles ve Policy isimlerinde birer property barındırmaktadır. Roles property’si sayesinde Role-Based Authorization yapabilmekteyiz. Policy property’si sayesindeyse Claim-Based Authorization ve Policy-Based Authorization yapabilmekteyiz.

Henüz bir role sahip olmadığımız için öncelikle kullanıcılarımızı listeleyelim. Sonrasındaysa rol ekleme sayfasını yazarak kullanıcılara rol atama işlemini gerçekleştirelim.

Kullanıcılarımızı UserManager<TUser> sınıfının Users property’si üzerinden, rollemiziyse RoleManager<TRole> sınıfının Roles property’si üzerinden listelemekteyiz. Kullanıcılarımızı listeleyecek view’ımızı oluşturalım.

Henüz AssignRoles sayfamız mevcut değil, rolle ilgili işlemler tamamlandığında yazılacaktır. Rollerimizi listeletecek view’ımızı oluşturalım.

Rollerimizi listeledik, rol oluşturacak action methodumuzu yazalım.

Rol oluşturmak için ilgili manager sınıfının CreateAsync methodunu kullanmaktayız.

Artık kullanıcılarımıza oluşturduğumuz rolleri atayabiliriz. AssisnRoles action methodunu yazalım.

Kullanıcıya rol atayacağımız view’ımızı tasarlayalım.

Kullanıcıya atanmış rollerin post edileceği ilgili Action methodumuzu yazalım.

Rollerimizi liste şeklinde alarak içerisinde dönüyoruz. İlgili rol seçilmişse AddToRoleAsync methoduyla kullanıcıya ekliyor aksi durumda RemoveFromRoleAsync methoduyla siliyoruz.

Role-Based Authorization

Kullanıcı ve rollerle ilgili işlemleri bitirdiğimize göre sayfalarımıza rol bazlı yetkilendirme uygulayarak kaynaklarımızı güven altına alabiliriz.

Bir controller sınıfı oluşturarak action methodlarımızı Authorize attribute’üyle işaretleyip ilgili rolleri Roles property’si üzerinden case-sensitive olarak verelim. Birden fazla rol verebiliriz.

İlgili role sahip olmayan kullanıcılar artık ilgili action methodlara erişemeyeceklerdir. Action methodları yerine controller sınıfı da doğrudan Authorize attribute’üyle işaretlenebilir. Bu durumda tüm action methodları yetkilendirmeye tabi olacaktır. Bu senaryoda dışarıya açmak isteyeceğimiz bir action methodumuz olursa [AllowAnonymous] attribute’ünü kullanmalıyız.

Claim-Based Authorization

Claim‘ler kullanıcılar hakkında key-value pair şeklinde bilgi tutan parçacıklardır. Bir içerik yönetim sistemimiz olduğunu düşünelim. Yeni kullanıcılara bir süreliğine yorum izni vermemek istiyorsunuz. Bunu rol bazlı yetkilendirme uygulayarak çözemeyiz. Kullanıcının üye olduğu tarihin claim olarak eklenerek claim bazlı yetkilendirme uygulanmalıdır. Rol bazlı yetkilendirme mekanizmasına esneklik katmaktadır.

Konuyu pekiştirmek adına kullanıcıya bağlı olduğu departmanı claim olarak ekleyelim ve sayfalara departman bazlı erişim sağlayalım.

Kullanıcıya atanmış claim’ler GetClaimsAsync methoduyla elde ediliyor. Claim’ler arasında departman claim’i varsa claim ReplaceClaimAsync methoduyla değiştiriliyor, yoksa AddClaimAsync methoduyla ekleniyor.

Claim bazlı yetkilendirme yapabilmek için Policy‘ler oluşturmalıyız. Bu işlem için AddAuthorization methodunun AuthorizationOptions property’sindeki AddPolicy methodundan faydalanacağız.

Claim bazlı yetkilendirme yapacağımız controller sınıfımızı oluşturarak action methodlarımızı Authorize attribute’üyle işaretleyip oluşturduğumuz policy’leri Policy property’si üzerinden belirtelim.

İlgili claim’e sahip olmayan kullanıcılar artık ilgili action methodlara erişemeyeceklerdir. Authorize attribute’ünü Policy değeriyle birlikte doğrudan controller sınıfına da verebiliriz.

Policy-Based Authorization

Policy oluştururken bir claim kontrolünden fazlasına ihtiyaç duyabilir ve bir takım koşulların gerçekleşmesini isteyebiliriz. Bu durumda ilke bazlı yetkilendirme kullanılarak gereksinimler karşılanmalıdır.

Öncelikle kullanıcı kayıt tarihini çalışma zamanında claim listemize eklememiz gerekmektedir. Bu işlem için IClaimsTransformation arayüzünü implemente eden bir sınıfa ihtiyaç duymaktayız.

İhtiyaç duyduğumuz claim’i eklediğimize göre karşılanması gereken koşulu belirtebiliriz.

Yukarıda öncelikle claim listemize eklediğimiz kayıt tarihi elde ediliyor. Sonrasındaysa üyeliğinden bu yana bir hafta geçip geçmediği kontrol ediliyor. Bir haftayı aşması durumunda koşul başarılı aksi durumda başarısız sayılacaktır.

Program.cs dosyası içerisinde gerekli düzenlemeleri yapalım.

Controller sınıfımıza ilgili action methodu ekleyerek Authorize attribute’ünün Policy property’sini ayarlayalım.

Kullanıcı üyeliği 7 günden fazla olmayan kullanıcılar artık ilgili action methodlara erişemeyeceklerdir.

Geliştirilen proje dosyalarına buradan ulaşabilirsiniz.

You may also like...

Bir cevap yazın

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