What is Json Web Token (JWT)? How to use in .Net Core (5.0)
Merhaba bu gönderide jwt hakkında bilgi vereceğim ve bununla ilgili örnek bir proje yapacağız
JWT Nedir?
Jwt, sunucu (server) ve istemci (client) arasında güvenlik bilgilerini paylaşmak için kullanılan açık bir standarttır. Her jwt bir json objesi içerir bu json objelerinde de bazı talepler (claims) vardır. Taleplerin değiştirilememesini sağlamak için de bir kriptografik algoritma ile şifrelenir.
Örnek Senaryo
Tüm ürünlerinizin döndüğü bir api olduğunu varsayalım bu servisden ürünleri çekebilmek içinde gerekli şart, kayıtlı kullanıcı olmak ve rolümüzün de yetkili personel olması. Her api isteğinde parametre olarak username ve şifre mantıken gönderilemez işlemi yapmaya hak kazanmak için :d bir tane biletimizin (token) olması gerekiyor bu bilet ile api isteklerini güvenli ve sorunsuz bir şekilde yapabiliriz. Token alacağımız servise username ve şifremizi güvenli bir şekilde göndeririz bilgilerimiz doğru ise servis bize bir bilet verir bu bilet bir Json Web Token’dir. (İleriki kısımlarda ayrıntıları var) Ürünler servisinin header bölümüne bu bileti ekleyerek isteği göndeririz eğer bilet geçerli ise servis ürünleri döner.
Örnek Bir Jwt Objesi
jwt objesi base64 ile şifrelenmiş üç bölümden oluşur:
- Header
- Şifreleme algoritması hakkında bilgi verir
- Payload
- Id, Username, Name gibi kullanıcı bilgileri döner
- Verify Signature
- Bu kısım en önemli yer, burayı dijital imza olarak tanımlayabiliriz. serverdan belirli bir key ile hashleyerek imza oluştulur bu imza sayesinde server doğrulama yapar. Örneğin name’i değiştirip bir encoding yaparsam tokenler değişecektir ve doğrulama başarısız olacaktır.
Asp.Net 5.0 Api Projesi ile Nasıl Kullanılır
Bundan sonraki anlatım kod üzerinden devam edeceğim, Şimdi Basit bir web api projesi yaparak kod tarafında nasıl kullanıldığını inceleyelim.
Visual studio üzerinden bir Asp.net 5.0 web api projesi oluşturarak başlıyoruz.
UserService adında bir sınıf ekleyelim.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
public interface IUserService { User AuthenticateUser(string firstname, string password); } public class UserService : IUserService { private readonly List<User> Users = new List<User> { new User { Id=1, Name="Okan", Surname="Karadağ", Username = "okank", Password="Test", //Normal şartlar altında db de hashli olarak tutulmalı } }; public User AuthenticateUser(string firstname, string password) { return Users.FirstOrDefault(u => u.Name == firstname && u.Password == password); } } |
Jwt ile ilgili bazı bilgililerimizi appsettings.json dosyasında tutacağız.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
{ "Logging": { "LogLevel": { "Default": "Information", "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information" } }, "AllowedHosts": "*", "JwtSettings": { "Issuer": "https://okankaradag.com", "Audience": "https://okankaradag.com", "SigningKey": "6543212548789413" } } |
JwtSettings objesini dotnet içinde daha kolay erişebilmek için bir sınıf yaratacağız ve daha sonra middleware’de bu sınıfla ilişkilendireceğiz.
1 2 3 4 5 6 |
public class JwtSettings { public string Issuer { get; set; } public string Audience { get; set; } public string SigningKey { get; set; } } |
Jwt ile ilgili konfigürasyonları yapalım. Middlewarede aşağıdaki gibi tanımları ekliyoruz
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
services.Configure<JwtSettings>(Configuration.GetSection("JwtSettings")); services.AddScoped<IUserService, UserService>(); services.AddAuthentication(auth => { auth.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; auth.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }) .AddJwtBearer(options => { options.SaveToken = true; options.TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = true, ValidIssuer = Configuration.GetSection("JwtSettings")["Issuer"], ValidateAudience = true, ValidAudience = Configuration.GetSection("JwtSettings")["Audience"], ValidateIssuerSigningKey = true, IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration.GetSection("JwtSettings")["SigningKey"])) }; }); |
Startup.cs’deki configure içine app.UseAuthentication() ve app.UseAuthorization() eklemelerini yapmayı unutmayınız
ilk satırda yukarıda bahsettiğim gibi appsettings.json‘daki JwtSettings sınıfı tanımladık. Token Validation Parametrelerinde yayımcı, izleyici(auidence) ve yayımcıya(issuer) özgün imzalı keyi tanımladık.
JwtHelper adında bir sınıf ile token üretimi yapacağız
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
public class JwtHelper { public static string GetJwtToken(string username, JwtSettings jwtSettings, TimeSpan expiration, Claim[] additionalClaims = null) { var tokenHandler = new JwtSecurityTokenHandler(); var claims = new[] { new Claim(JwtRegisteredClaimNames.UniqueName,username), new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()) }; if (additionalClaims is object) { var claimList = new List<Claim>(claims); claimList.AddRange(additionalClaims); claims = claimList.ToArray(); } var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSettings.SigningKey)); var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256); var token = new JwtSecurityToken( issuer: jwtSettings.Issuer, audience: jwtSettings.Audience, expires: DateTime.UtcNow.Add(expiration), claims: claims, signingCredentials: creds ); ; return tokenHandler.WriteToken(token); } } |
Claim kısmına iki tane unique değer ekledik böylece tokenlerin aynı olabilme ihtimalini sıfırladık. settings kısmında yazdığımız bilgiler ve Sha256 algoritmasını kullanarak bir token nesnesi oluşturduk fakat bu token bilgisinde nerdeyse bütün bilgiler olduğu için WriteToken metodu ile son kullanıcıya geçecek tokeni oluşturmuş olduk.
AccountController ekleyip bir token almaya deneyelim.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
[Route("[controller]")] [ApiController] public class AccountController : ControllerBase { private IUserService UserService; private JwtSettings JwtSettings; public AccountController(IUserService userService, IOptions<JwtSettings> jwtSettings) { UserService = userService; JwtSettings = jwtSettings.Value; } [HttpPost("login")] public IActionResult Login([FromBody] LoginModel loginModel) { var user = UserService.AuthenticateUser(loginModel.Username, loginModel.Password); if (user == null) { return BadRequest(new { message = "Username or password is incorrect" }); } var claims = new List<Claim>(); claims.Add(new Claim("username", user.Username)); claims.Add(new Claim("displayname", user.Name)); var token = JwtHelper.GetJwtToken(user.Username, JwtSettings, new TimeSpan(0, 15, 0), claims.ToArray()); return Ok(token); } } |
Claim olarak username ve displayname ekledim isterseniz roles türünde rolleri de tanımlayabilrsiniz.
Postman ile token isteği
Aldığımız tokeni jwt.io sayfasında decode edince aşağıdaki sonuç çıkacaktır.
Tokeni aldık şimdi sıra kullanmaya geldi. Dotnetin otomatik oluşturduğu WeatherForecast adında bir api authorize attribute koyacağız
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
[ApiController] [Route("[controller]")] public class WeatherForecastController : ControllerBase { private static readonly string[] Summaries = new[] { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" }; private readonly ILogger<WeatherForecastController> _logger; public WeatherForecastController(ILogger<WeatherForecastController> logger) { _logger = logger; } [Authorization] [HttpGet] public IEnumerable<WeatherForecast> Get() { var rng = new Random(); return Enumerable.Range(1, 5).Select(index => new WeatherForecast { Date = DateTime.Now.AddDays(index), TemperatureC = rng.Next(-20, 55), Summary = Summaries[rng.Next(Summaries.Length)] }) .ToArray(); } } |
Postman üzerinde WeatherForecast’e istek gönderelim
Aldığımız tokeni headerse bearer token etiketine yazdık ve doğrulama başarılı oldu. Eğer ki tokende ufak bir değişiklik yaparsak 401 dönecektir.
Project url : okankrdg/JwtExampleProject (github.com)
Yazının sonuna geldik başka bir makalede görüşmek üzere 🙂
Merhaba çok araştırdım ama bir sonuç elde edemedim. Bir Mvc Web App oluşturup Authentication ve işte rölü admin olanlar gibi bir senaryoyu hayata geçiremedim acaba yardımcı olurmusunuz. Teşekkürler.
merhaba, şu linkten detaylı olarak açıklaması var bakabilirsiniz https://okankaradag.com/asp-net/asp-net-core/asp-net-core-rol-bazli-kimlik-dogrulama
deli olacam tokeni olusturuyorum ama kullanamıyorum hatta proje indiriyorum örnek calıstırıyorum localde postman dan baglanıyorum yine olmuyor anlamadım gitti bir türlü.
github projesini incelediniz mi:https://github.com/okankrdg/JwtExampleProject ya da hatayla ilgili spesifik bir sorun yazarsanız daha iyi yardımcı olabilirim
merhaba, ben sizin projenizi indirdim ve token aldıktan sonra diger method hiç bir sekilde tepki vermiyor.
github projesini incelediniz mi:https://github.com/okankrdg/JwtExampleProject ya da hatayla ilgili spesifik bir sorun yazarsanız daha iyi yardımcı olabilirim