Merhaba arkadaşlar,
Bugün sizlere ASP.NET MVC Core 5.0‘da Cookie Authentication yapısını Asp.Net Core Identity olmadan kendimiz özel şekilde nasıl yönetiriz anlatmaya çalışacağım.
Cookie Authentication, tarayıcıların Çerez Depolarını kullanarak, oturum yönetme imkanı veren bir Authentication yapısıdır. Bu yapıyı Identity içerisindeki Claimler ile yönetmektedir.
Şimdi başlayalım
1- Öncelikle Asp.Net Mvc Core 5.0 olarak yeni bir proje oluşturdum.
2- Startup.cs dosyamın içerisindeki, ConfigureServices methoduna, commentlediğim kısımları ekliyorum.
Burada Cookie Authentication şemasını kullanacağımı belirten temel ayarları yapıyorum.
public void ConfigureServices(IServiceCollection services) { services.AddControllersWithViews(); // + Cookie Auth services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) .AddCookie(opt => { opt.LoginPath = "/Account/Login/"; }); // - }
3- Startup.cs içerisindeki Configure methodunun içine commentlediğim kısmı ekliyorum.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/Home/Error"); // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. app.UseHsts(); } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); // + Cookie Auth app.UseAuthentication(); // - app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); }); }
app.UseAuthentication(); satırının, app.UseAuthorization(); üzerinde olmasının önemi vardır. Buna göre sistem bu authentication yöntemini kullanarak, authorizationı yöneteceğini anlamış oluyor.
Temel ayarlarmız hazır. Herhangi bir Controller’a gidip [Authorize] attribute özelliğini eklediğimizde, kullanıcı giriş yapmamış ise, otomatik olarak, Startup.cs‘de belirtmiş olduğumuz, Account/Login sayfamıza yönlenecek. Henüz böyle bir sayfa eklemediğimiz için haliyle bu sayfayı bulamayacaktır.
Devam edelim.
4- Model klasörümün içine LoginRequest.cs isimli bir class ekliyorum.
using System.ComponentModel.DataAnnotations; namespace CookiesAuthTutorial.Models { public class LoginRequest { [Required(ErrorMessage = "Username is required.")] public string Username { get; set; } [Required(ErrorMessage = "Password is required.")] public string Password { get; set; } } }
5- Yeni bir Controller ekliyorum. İsmini AccountController yapıyorum.
Login, Logout methodlarımı ekliyorum. Controllerımın tam hali;
using CookiesAuthTutorial.Models; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Mvc; using System.Collections.Generic; using System.Security.Claims; using System.Threading.Tasks; namespace CookiesAuthTutorial.Controllers { public class AccountController : Controller { [HttpGet] public IActionResult Login() { return View(); } [HttpPost] public async Task<IActionResult> Login(LoginRequest loginRequest) { if (ModelState.IsValid) { if (loginRequest.Username == "Semih" && loginRequest.Password == "123") { var claims = new List<Claim> { new Claim(ClaimTypes.NameIdentifier, loginRequest.Username), new Claim(ClaimTypes.Name, loginRequest.Username) //new Claim(ClaimTypes.Email, "email") //new Claim("FullName", user.FullName), //new Claim(ClaimTypes.Role, "Administrator"), }; var claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme); var authProperties = new AuthenticationProperties { //AllowRefresh = <bool>, // Refreshing the authentication session should be allowed. //ExpiresUtc = DateTimeOffset.UtcNow.AddMinutes(10), // The time at which the authentication ticket expires. A // value set here overrides the ExpireTimeSpan option of // CookieAuthenticationOptions set with AddCookie. //IsPersistent = true, // Whether the authentication session is persisted across // multiple requests. When used with cookies, controls // whether the cookie's lifetime is absolute (matching the // lifetime of the authentication ticket) or session-based. //IssuedUtc = <DateTimeOffset>, // The time at which the authentication ticket was issued. //RedirectUri = <string> // The full path or absolute URI to be used as an http // redirect response value. }; await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(claimsIdentity), authProperties); return RedirectToAction("Index", "Home"); } else { ModelState.AddModelError("Password", "Username or Password wrong !"); } } return View(); } public async Task<IActionResult> Logout() { await HttpContext.SignOutAsync(); return RedirectToAction("Login"); } } }
Claim satırları bizler için kritik olan satırlardır. Buradaki Claim bilgilerini cookielerde saklayarak giriş yaptıktan sonra buraya ne yazmışsak, erişebilir hale getirmiş olacağız. Bu yüzden kullanıcı adı, email gibi uniq değer içeren verileri bu claimlere set etmemiz gerekiyor ki, kullanıcıları claimler içinde de ayırt edebilelim. Ben bu örnekte, kullanıcı adını set etmiş oldum.
Ek olarak Claimler ile ilgili şunlarıda söylemek isterim, Claim içerisinde tanımlı gelen defautl Enum değerleri olsada, özel olarak bizlerde, key, value şeklinde bir claim oluşturabiliyoruz.
AuthProperties kısmından ise, kullanıcının oturumuyla alakalı belirli ayalarları yapabiliriz. Ben default olarak bıraktım.
6- View kısmınının yapılması. View’lara Account isimli bir klasör açıyorum, içine Login.cshtml isimli dosyamı oluşturuyorum.
Login.cshtml dosyamın içeriği;
@model CookiesAuthTutorial.Models.LoginRequest @{ Layout = ""; ViewBag.Title = "Login"; } <head> <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" /> </head> <div class="container"> <form asp-controller="Account" asp-action="Login" method="post"> <div class="form-group"> <label for="Username">Username</label> <input type="text" class="form-control" asp-for="Username" placeholder="Enter Username"> <span asp-validation-for="Username" class="alert-danger"></span> </div> <div class="form-group"> <label for="exampleInputPassword1">Password</label> <input type="password" class="form-control" asp-for="Password" placeholder="Enter Password"> <span asp-validation-for="Password" class="alert-danger"></span> </div> <button type="submit" class="btn btn-primary">Submit</button> </form> </div>
Evet işlemler bu kadar, artık hazırız.
Eğer kullanıcı adı ya da şifre yazmamış isek, ModelState‘imiz otomatik olarak yakalıyor ve LoginRequest model üzerinde belirttiğimiz hatayı ekrana basıyor.
Kullanıcı adımız veya şifremiz yanlış ise, Custom olarak yazdığımız hatayı ekrana basıyor.
Doğru ise, kullanıcıyı Home sayfasına yönlendiriyoruz.
_layout.cstml’de dosyama, giriş yapan kullanıcıyı gösteren şu satırı ekledim.
<p>Hoş geldin @User.Identity.Name <a href="Account/Logout">Çıkış yap</a></p>
Controller tarafında, herhangi bir claim değerini çekmek istiyorsak, aşağıdaki kod ile bunu yapabiliriz.
var name = User.Claims.Where(x => x.Type == ClaimTypes.Name).FirstOrDefault().Value;
Bu kod bize, Claim içinde Name alanına yazmış olduğumuz değeri verir. Eğer Custom bir değeri Claimlere set etmiş isek. Bu kez x.Type == “CustomClaimKey” şeklinde istediğimiz değeri çekebiliriz.
İşlemler bu kadardır. Umarım faydalı olur.
Bu projenin tamamına Github sayfamdan erişebilirsiniz. Link: https://github.com/semihcelikol/CookiesAuthTutorial
Yararlandığım kaynaklar
https://docs.microsoft.com/en-us/aspnet/core/security/authentication/cookie?view=aspnetcore-5.0
Semih bey core 6 ile identity yönetimi ile api oluşturdum ama bir türlü mvc web app ile oturum acamadım vaktiniz olursa bir makale ile yardımcı olurmusunuz. teşekkürler
Merhaba Recep bey,
Yorumunuz için teşekkürler. Şuanda maalesef böyle bir yazı planlamıyorum fakat jwt token ile bağlantı yapabileceğiniz bir çok araç mevcut. Öncelikle bu araçlar ile yapmış olduğunuz api’ye bağlanmayı denemenizi tavsiye ederim. Örneğin Postman gibi bir tool ile apinize bağlanmayı ve methodlarınızı test etmenizi tavsiye ederim. Böylece sorunlarınızın api’den kaynaklı olup olmadığını anlamış olacaksınız.
Teşekkürler.
merhaba, günlerdir authentication problemini çözmeye çalışıyordum. app.UseAuthentication(); satırının, app.UseAuthorization(); üzerinde olması gerektiğini hiçbir yerde görememiştim. detaylı ve güzel anlatımınız için çok teşekkür ederim.
Merhaba,
Rica ederim. Yorumunuz için teşekkürler.
anlatımınız için teşekkür ederim, emeğinize sağlık.
Rica ederim. İyi çalışmalar dilerim.