Asp.Net Core JSON Web Token Kullanımı

Bu yazımızda asp.net core uygulamalarında token based authentication nedir, nasıl sağlanır bir örnek üzerinden inceleyeceğiz. 

ProductApi adında bir service projenizin olduğunu düşünün ve bu service üzerinde product tablonuz için CRUD işlemlerini yapan belli endpoint'ler sağladığınızı varsayalım. Herhangi bir güvenlik kontrolü bulunmayan ProductApi'nize call yapmak isteyen bir kişi geliştirme yaparken doğrudan erişebiliyor. Peki ama çok basit bir şekilde düşünecek olursak service url'lerini bulan herhangi bir kişi servisinizi manipüle etmek adına CRUD metotlarınıza doğrudan call yapabilir yada bazı metotları call edebilir bazılarını edemez vs. gibi riskler barındırmaktadır.

Bu gibi durumlara çözüm olarak token-based authentication yöntemleri geliştirilmiştir.

Token based authentication'ın genel konsepti oldukça basit; kullanıcıdan bir username ve password vs. gibi bir bilgi alıp bu bilgiyi server'a göndermek ve eğer valid bir username ve password ise karşılığında bir token dönüp o kullanıcının artık token expire oluncaya dek bütün api işlemlerini o token üzerinden yapması beklenir. 

JSON Web Token Nedir Nasıl Kullanılır;

Base64 olarak oluşturulmuş 3 ayrı bölümden oluşur;

HEADER.PAYLOAD.SIGNATURE

Header bölümünde; hangi token türünün ve şifreleme algoritmasının kullanıldığı bilgisi yer alır.

Payload; uygulama bazlı bilgilerin yer aldığı(claim,userId vs.) yani uygulamaya özel bölümdür.

Signature ise adından da anlaşıldığı gibi server tarafından üretilen signature'ın bulunduğu bölümdür.

 

Şimdi ise bir asp.net core projesinde JWT nasıl entegre edilir ve kullanılır bunu inceleyelim. 

İlk olarak aşağıdaki gibi Startup.cs bulunan ConfigureServices metodu içerisinde uygulama boyunca geçerli olan JWT Authentication middleware konfigurasyonlarını yapalım.

public void ConfigureServices(IServiceCollection services)
{
    services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(jwtBearerOptions =>
    {
        jwtBearerOptions.TokenValidationParameters = new TokenValidationParameters()
        {
            ValidateActor = true,
            ValidateAudience = true,
            ValidateLifetime = true,
            ValidateIssuerSigningKey = true,
            ValidIssuer = Configuration["Issuer"],
            ValidAudience = Configuration["Audience"],
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["SigningKey"]))
        };
    });
    services.AddMvc();
}

Middleware tanımlamasını yukarıdaki gibi yaptıktan sonra bunu builder'a eklememiz gerekmekte. Bunun içinde yine Startup.cs de Configure metodu içerisinde aşağıdaki tanımlamayı yapalım.

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    app.UseAuthentication();
    app.UseMvc();
}

Sırada JWT generate edecek olan endpoint'i oluşturma var. Bunun için TokenController adında bir controller oluşturalım ve içerisine kullanıcıyı validate ederken kullanılacak olan bilgilerin bulunduğu request modeli alıp geriye tokenResponse dönen bir endpoint oluşturalım.

[AllowAnonymous]
[HttpPost]
[Route("token")]
public IActionResult Post([FromBody]LoginRequest request)
{
    if (ModelState.IsValid)
    {
        var user = _userService.Get(request.UserName, request.Password); 
        if (user == null)
        {
            return Unauthorized();
        }

        var claims = new[]
        {
            new Claim(JwtRegisteredClaimNames.Sub, request.Username),
            new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())
        };

        var token = new JwtSecurityToken
        (
            issuer: _configuration["Issuer"], //appsettings.json içerisinde bulunan issuer değeri
            audience: _configuration["Audience"],//appsettings.json içerisinde bulunan audince değeri
            claims: claims,
            expires: DateTime.UtcNow.AddDays(30), // 30 gün geçerli olacak
            notBefore: DateTime.UtcNow,
            signingCredentials: new SigningCredentials(new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["SigningKey"])),//appsettings.json içerisinde bulunan signingkey değeri
                    SecurityAlgorithms.HmacSha256)
        );
        return Ok(new { token = new JwtSecurityTokenHandler().WriteToken(token) });
    }
    return BadRequest();
}

public class LoginRequest
{
	public string UserName {get;set;}
	public string Password {get;set;}
}

JWT based authentication yapısı projemiz için hazır. Sırada bunu test etmek var. Bunun için asp.net core projesi oluşturulurken default gelen ValuesController.cs içerisindeki Get metodunu kullanarak testimizi yapalım. Controller seviyesinde [Authorize] atrtribute'ü kullanarak authentication zorunlu olduğunu belirtebiliriz.

[Authorize]
[Route("api/[controller]")] 
public class ValuesController : Controller
{
    [HttpGet]
    public IEnumerable<string> Get()
    {
        return new string[] { "value1", "value2" };
    }
}

Postman kullanarak projemizi test edelim.

İlk olarak token almadan ValuesController'a HttpGet request'inde bulunalım ancak token bilgisi set etmediğimizden bize geriye successful bir response (http200) dönmemesi gerekir. Aşağıda görüldüğü üzre response olarak 401 yani Unauthorized cevabı aldık.

Şimdi ise TokenController da bulunan metoda request atarak token response'unu aşağıdaki gibi alalım.

Almış olduğumuz tokenResponse'u göndereceğimiz request'in Authorization header'ına set ederek tekrardan ValuesController'a istekte bulunduğumuzda bu sefer http200 ile geriye value array'ini dönen cevabı almış olacağız.

JWT'nin kullanımı özetle bu şekilde. Sizlerde geliştirdiğiniz bir api projenizi dış dünyaya açarken token-based authentication yapmak istediğinizde implementasyonu oldukça basit olan basit jwt den faydalanabilirsiniz.

Comments (16) -

  • Merhaba hocam  cok guzel anlatmissiniz.   _userService     yazmissiniz  token controller  içinde  .bu degiskenmi .  Bu nerde geliyor.   Bende hata verdi. Merak ettim. Tsk ederim

    • Merhaba, değerli yorumun için teşekkürler. O service layer'ınızda bulunan herhangi bir service'in instance'ı aslında, business layer olarakda düşünebilirsiniz örnek olması açısından oluşturmuştum.
  • hocam çok teşekkür ederim sırf su konuyu öğrenmek için udemy den bir ders almıştım orda token oluşturma yı göstermişti ancak token ile işlem yapmamıştı class'ın başına sadece [Authorize] eklemem yetiyormuş çok sağolun
    • Değerli yorumun için teşekkürler Smile
  • Selam Cihan, çok faydalı bir içerik olmuş yalnız _configuration["SigningKey"] değerini nasıl aldığını da gösterebilirsen (hem controller'da hem startup'da) eksikliği gidermiş olursun bence..
    Kolay gelsin !
  • Hocam JWTde yeniyim. Bu örneği tüm dosyaları ile paylaşabilir misiniz? _userservice ve _configuration kısmını tam olarak anlamadım.
    • UserService dummy olarak yazdığım bir sınıf, kısaca içerisinde kullanıcı bilgisini aldığın bir metot olan sınıf gibi düşünebilirsin
      _configuration ise .net core'un kendi configurationSource sınıfı. Kısaca appSettings değerlerine erişmeni sağlar
  • Hocam merhaba, ben sistemde oturum açmış kullanıcının id sini almak istiyorum.
    Örneğin bir içerik eklenirken ekleyen kişinin id sinide eklemek istiyorum. Bu id ye nasıl ulaşabilirim ?
    • Merhaba,
      Aslında sana kalmış, bu bilgiyi kullanıyı login yaptıktan sonra token(jwt yada diğer türler olabilir) içerisinde saklayabilirsin ve ihtiyacın olduğunda da kullanabilirsin.
  • Caner Bey.
    _userservice kısmı nı da dummy değilde gerçekten bir örnek mahiyetinde yapsaydınız güzel olurdu. ilk başlayanlar için bu eksik kalmış gibi olmuş. bu kadar yazmışsınız elinize sağlık örnek proje dosyası linki verseydiniz tam süper olurdu.
    teşekkürler
  • Merhabalar,
    Proje IIS Express de debug ederken çok güzel çalışıyor ama aynı kodu Publish ile IIS de servis edildiğinde [AllowAnonymous] işaretli metodlara 404 Not Found cevabı veriyor
    • Merhaba kullanmış olduğun framework ile ilgili. Hangi versiyonu kullanıyorsan nuget üzerinden search etmeyi deneyebilirsin.
  • Mrb, olusturdugun token projene yapilacak her requestte gonderilmeli ki her seferinde kontrol edebilesin. Send jwt to request seklinde Google’larsan ornek bulabilirsin.

Add comment