Caner Tosuner

Leave your code better than you found it

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.

Yorumlar (10) -

  • Ilhan

    21.09.2018 09:29:20 | Yanıtla

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

    • Caner

      24.09.2018 09:39:11 | Yanıtla

      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.

  • Eray Han

    1.10.2018 16:21:51 | Yanıtla

    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

    • Caner

      1.10.2018 18:56:27 | Yanıtla

      Değerli yorumun için teşekkürler Smile

  • Emre

    22.04.2019 00:10:45 | Yanıtla

    Hocam JWTde yeniyim. Bu örneği tüm dosyaları ile paylaşabilir misiniz? _userservice ve _configuration kısmını tam olarak anlamadım.

    • Caner

      20.05.2019 10:18:16 | Yanıtla

      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

  • Furkan

    23.04.2019 10:17:48 | Yanıtla

    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 ?

    • Caner

      16.08.2019 14:45:42 | Yanıtla

      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.

  • Mustafa Aktepe

    13.06.2019 16:22:29 | Yanıtla

    Teşekkürler. Faydalı bir yazı olmuş.

  • Gündoğdu

    20.06.2019 23:48:08 | Yanıtla

    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

Yorum ekle

Loading