C# — JSON Web Token(JWT) Ve WebApi Örneği

Engin UNAL
10 min readAug 29, 2023

--

JSON Web Token Nedir? Detaylı inceleyip WebApi ve .Net tarafındaki kullanım örneği ile yazıyı sonlandıracağız.

JWT yani JSON Web Token, verilerin taraflar arasında(alıcı-verici veya istemci-sunucu vb. olabilir) güvenli iletilmesi için tanımlanmış açık bir standarttır. Bu bilgiler dijital olarak imzalandığı için doğrulanabilir ve değiştirilmeye karşı güvenlidir. İmzalama için simetrik bir anahtar — Secret Key — (HMAC algoritmasıyla) veya Özel/Genel Anahtar Çifti — Private/Public Key Pair — (RSA veya ECDSA algoritmasıyla) kullanılabilir.

JWT kullanılan bir servis çağrısı örneği

Ağırlıklı olarak kullanım alanları; Kimlik doğrulama, servis güvenliği, kaynak erişimi yetki kontrolü, servisler arası iletişimde güvenli iletişim ve mesajın bütünlüğünün garanti edilmesi durumu olarak özetlenebilir.

Bu yazıda örnek olarak seçeceğim kullanım ise bir webapi projesindeki kimlik doğrulama ve api erişim kontrolü olacaktır.

JWT İç Yapısı

JSON Web Token üç ana parçadan oluşmaktadır. Bunlar Header, Payload ve Signature olarak sıralanabilir.

JWT içeriği

Bu üç veri katmanı Base64 formatındadır ve aralarında “.” (nokta) ayracı vardır. Aşağıdaki örnekte jwt.io sitesindeki decoder ile token ve içeriği gösterilmiştir.

jwt.io

Header

Header verisi için genel olarak iki alan ön plana çıkmaktadır.

  • alg : İmzalama veya şifreleme algoritması. (HS256, RS256, ES256)
  • typ : Token’ın tipi yani JWT.
{
“alg”: “HS256”,
“typ”: “JWT”
}

Algoritma seçimi nasıl yapılır? Bunu Signature konusu devamında inceleyeceğiz.

Payload

Payload, token içindeki verinin taşındığı alandır. İçinde claim yapıları bulunur. Aynı header gibi JSON formatındadır. Payload içindeki claim’lerin bazıları ön tanımlı veya kayıtlı olmakla birlikte ihtiyaca göre kullanıcı tanımlı claim’ler de eklenebilir. Önemli olan kayıtlı bir claim ile aynı isimde kullanmamaya dikkat edilmelidir(detay). Kayıtlı claim’lerden bazıları ve açıklamaları aşağıda listelenmiştir. Bunlar zorunlu değildir fakat kullanılması standardizasyon açısından önerilir.

  • iss : Issuer — Token’ı oluşturan veya yayınlayıcının adı.
  • sub : Subject — Alıcı. Token’ın kim için oluşturulduğu bilgisini tutar.
  • aud : Audience — Hedef kullanıcı, alıcı. Sadece buradaki kullanıcılar tarafından kullanılabilir.
  • exp : Expiration Time — Son kullanım tarihi.
  • nbf : Not Before — Verilen süreden öncesinde geçerli değil bilgisini tutar.
  • iat : Issued At — Token oluşturulma zamanı.
  • jti : JWT ID — Benzersiz kimlik değeri.

Signature

JWT verisinin imzasını taşıyan bölümdür. Burada token’ın imzası bulunur. Token’ın üreticisinin ve token bütünlüğünün kontrolünün yapılabilmesi signature verisi ile mümkün olmaktadır. Örneğin HMAC algoritması ile imzalama yapmak istersek aşağıdaki gibi bir yol izleriz.

HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
SECRET_KEY
)

Şimdi biraz algoritma detaylarına ve seçiminin nasıl yapılabileceğine değinelim.

Algoritma Seçimi

İmzalama işlemlerinde, jwt içindeki header ve payload verileri alınır ve hash işleminden geçirilir devamıda bu veri imzalanır. Hash nedir? Öncelikle bunu hatırlayarak başlayalım.

Hash, bir veriyi boyutuna bağlı olmadan hep aynı uzunlukta bir çıktıya çeviren yani verinin parmak izini alan matematiksel fonksiyonlardır. Tek yönlü şifreleme yapar. Hash değerinden orjinal veriye ulaşmak mümkün değildir. Bu nedenle genellikle veri bütünlüğü kontrollerinde tercih edilir. Hash değerinin alınmasının önemli nedenlerinden biri de büyük boyutlu verinin tamamının şifrelenmesi yerine hash değerinin hesaplanarak çok daha verimli kontrollerin yapılabilmesini sağlamaktır.

Örneğin bir dosyanın değişmemesini istiyoruz ve bunu kontrol etmemiz gerekiyor. Bunun için hash değerini alıp saklarız. Eğer dosyada değişiklik olursa dosyanın güncel hash değerini hesaplatıp eskisiyle kıyaslayarak dosyanın orjinal olup olmadığını anlayabiliriz. Hash verisi hep aynı uzunlukta olacağından yani hash’i alınmak istenen verinin boyutundan bağımsız olacağından oldukça verimli bir yöntemdir.

Hash algoritması için JWT tarafında genellikle SHA-256, SHA-384, SHA-512 gibi seçenekler vardır bunlar SHA-2 hash algoritma ailesindendir. Buradaki numaralar üretilen hash verisinin boyutunu verir.
Örneğin SHA-256, 256-bit’lik bir hash üretirken SHA-512 ise 512-bit’lik hash üretmektedir.

JWT tarafında da hash işlemleri token bütünlüğünün kontrol edilmesi ve token üreticisinin doğrulanması için kullanılır. Konunun başında belirttiğim gibi token hash değeri alınır ve bu veri şifreleme algoritmasından geçirilerek şifrelenir ve token imzası yani Signature bölümüne yazılır.

İmzalama için kullanılabilecek algoritmalar kullanım alanlarına ve güvenlik seviyelerine göre farklılıklar göstermektedir.

HMAC

Simetirk şifreleme algoritmasıdır. Hash-based Message Authentication Codes kelimelerinin kısaltılmışıdır. Hash algoritması olarak HS256 için SHA-256, HS384 içi SHA-384 ve HS512 için SHA-512 kullanılır. Simetrik kriptografi ile anahtar(Secret Key) ve hash fonksiyonunu alarak mesajın güvenlik kodunu oluşturur.

İmzayı oluşturmak ve doğrulamak için aynı anahtarı kullanır. Anahtarın, imzalayıcı ve doğrulayıcı arasında paylaşılması güvenli olmadığından genellikle iç kullanımlarda tercih edilir.

RSA

Asimetrik şifreleme algoritmasıdır, yaygın olarak kullanılır. Adını bulucularının(Rivest–Shamir–Adleman) soyisimlerinin baş harflerinden almıştır. Temelindeki mantık bir anahtar ile şifrelenen verinin tekrar aynı anahtar ile çözülmesine ihtiyaç duymamasıdır. Bu anahtarlar private key ve public key çiftidir. Public key ile şifrelenen veri private key ile çözülebilir.
İmzalama işlemlerinde ise private key ile imzalanan veriler public key ile doğrulanır. Böylece private key’in karşı tarafa verilmesi gerekemez.

Genel anahtar kriptografi standardı(Public Key Cryptography Standard 1- PKCS #1) RSA algoritması kullanımına ilişkin şifreleme şemaları, formatları vs. bir çok standart belirlemiştir.
RSASSA’da bu tanımlamalardan biridir, RSA imzalarının ve doğrulamasının standartlarını belirler. RSASSA — RSA Signature Scheme With Appendix.

Burada önemli nokta RSASSA PKCS1 v1.5 ile deterministik imzalama yapılmaktadır.

Bu ne demek? Yani aynı header ve payload değerlerine sahip JWT imzaları aynı olacaktır.

JWT için seçenekler:

  • RS256: RSASSA PKCS1 v1.5 — SHA-256
  • RS384: RSASSA PKCS1 v1.5 — SHA-384
  • RS512: RSASSA PKCS1 v1.5 — SHA-512

İmzaların daha güvenli olmasına imkan tanımak için RSASSA-PSS seçeneği de mevcuttur. RSASSA-PSS, RSA’nın olasılıksal versiyonudur. Buradaki PSS, Probabilistic Signature Scheme kelimelerinin kısaltılmışıdır.
Kriptografik olarak rastlantısal numara üreteci(RNG-Random Number Generator) kullanır. Bu nedenle imzalanan veri içeriği değişmese de imza değişir. Yani aynı header ve payload verisine sahip JWT her imzalamada farklı bir imza değeri üretir.

Daha güvenli olması nedeniyle RSASSA-PSS’in kullanımı önerilmektedir.

JWT için seçenekler:

  • PS256: RSASSA-PSS — SHA-256
  • PS384: RSASSA-PSS — SHA-384
  • PS512: RSASSA-PSS — SHA-512

ECDSA

RSA gibi asimetrik şifreleme algoritmalarından biridir. Adını Elliptic-Curve Digital Signature Algorithm kelimelerinin ilk harfnden alır. RSA’daki gibi asal çarpanlarını kullanmak yerine eliptik eğriler(y2 = x3 + ax + b) üzerinde inşa edilmiştir.

RSA’ya göre avantajları ise kırılma olasılığı daha düşük olmakla birlikte daha kısa şifre anahtarı kullanır bu nedenle imza boyutu küçüktür. Örneğin 256-bit’lik bir Elliptic-Curve anahtarının sağladığı güvenlik için RSA tarafında 3072-bit gereklidir. Artısı yanında eksisi de var. İmzalamada hızlı olsa da imza doğrulamada RSA’a göre daha yavaştır. Ek olarak rastlantısal sayı üretimi imzanın güvenliği açısından kritiktir. Bu noktada RSA daha iyidir.

JWT için seçenekler:

  • ES256: ECDSA — SHA-256
  • ES384: ECDSA — SHA-384
  • ES512: ECDSA — SHA-512

Özet

Eğer JWT ile güvenlik gerektiren işlemler yapılmakta ise yani iç kullanım gibi daha düşük güvenlik seviyesi gerektiren bir kullanım değilse ES veya PS tercih edilmelidir. Bu noktada algoritmaların arasında seçim için daha detaylı düşünmek gerekir. Örneğin imzalama işleminin yavaş olması önemli değil fakat doğrulama işleminin hızlı olması önemli bir durum ise PS daha iyi bir seçim olacaktır. Veya imza boyutu küçük olmalı ise ES iyi bir seçim olabilir. HMAC gibi seçimler yani simetrik anahtar ile şifreleme çözümleri dış kullanımlar için önerilmez.

Kodlama örneğimizle devam edelim.

JWT & WebApi Örneği

Kodlama örneğimizde daha önceden hazırda tuttuğum temel bir webapi projesini kullanacağım. İsterseniz aşağıda paylaştığım linkten siz de aynı şekilde ilerleyebilirsiniz.

https://github.com/enginunal/AspNetJWT/tree/webapi-base

Temel webapi projesinde sadece Item CRUD işlemi bulunuyor.

Bu webapi projesinde item tablosu var ve servisteki CRUD(Create, Read, Update, Delete) fonksiyonları ile tablodan okuma ve tabloya yazma gibi temel işlemler bulunuyor. Bunu da ItemsController ile yapıyoruz. Veritabanı olarak SqLite kullandım. Bu kısa tanıtımdan sonra amacımıza geçelim.

Item servisimize sadece izin verdiğimiz ve token sahibi olanların erişmesini istiyoruz yani güvenlik katmanı ekleyeceğiz. Bunu da JWT ile sağlayacağız. Öncelikle JWT kütüphanelerimiz ekleyelim.

dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer --version 7.0.10
dotnet add package System.IdentityModel.Tokens.Jwt --version 6.32.2

appsettings.json dosyasında jwt tanımlarımızı yapalım. Bunları token üretirken kullanacağız.

"JwtTokenOptions": {
"Issuer": "AspNetJWT",
"Audience": "ItemsAud",
"SigningKey": "simetrik sifreleme anahtari kullanacagiz",
"Expiration": 3600
}

Program.cs dosyasına aşağıdaki tanımları ekleyelim.

builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(opts =>
{
byte[] signingKey = Encoding.UTF8
.GetBytes(builder.Configuration.GetSection("JwtTokenOptions")["SigningKey"]);

opts.TokenValidationParameters = new TokenValidationParameters
{
ValidIssuer = builder.Configuration.GetSection("JwtTokenOptions")["Issuer"],
ValidAudience = builder.Configuration.GetSection("JwtTokenOptions")["Audience"],
IssuerSigningKey = new SymmetricSecurityKey(signingKey)
};
});
builder.Services.AddAuthorization();
//Swagger için gerekli tanımları da ekleyelim. Bunu swagger üzerinden
//token denemesini yapmak için ekledim. Postman kullanıyorsanız gerek yok.
builder.Services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "AspNetJWT", Version = "1.0" });
c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
{
Name = "Authorization",
Type = SecuritySchemeType.ApiKey,
Scheme = "Bearer",
BearerFormat = "JWT",
In = ParameterLocation.Header,
Description =
"JWT Authorization header using the Bearer scheme. \r\n\r\n Enter 'Bearer' [space] and then your token in the text input below.\r\n\r\nExample: \"Bearer 12345abcdef\""
});
c.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "Bearer"
}
},
new string[] { }
}
});
});
//...
//...
//bunlar mutlaka aşağıdaki sırayla olmalı
app.UseAuthentication();
app.UseAuthorization();

Tanımlar bu kadar. Şimdi token üretimi yapabilmek için bir controller ekleyelim. Bunun adı TokenController olsun.

dotnet aspnet-codegenerator controller -name TokenController -async -api -outDir Controllers

TokenController.cs dosyamıza aşağıdaki metodları ekleyelim. (Not: Tabi burada constructor içinde IConfiguration config de enjekte edilmeli).

[HttpGet("{pwd}")]
public async Task<IActionResult> GetToken(string pwd)
{
if (pwd != "123") return Unauthorized("Şifre geçersiz.");
string token = GenerateToken();
return Ok(token);
}

private string GenerateToken()
{
var keyBytes = Encoding.UTF8.GetBytes(_config.GetSection("JwtTokenOptions")["SigningKey"]);
var symmetricKey = new SymmetricSecurityKey(keyBytes);

var signingCredentials = new SigningCredentials(
symmetricKey,
SecurityAlgorithms.HmacSha256);

var claims = new List<Claim>()
{
new Claim("sub", "eunal"),
new Claim("name", "engin unal")
};

var roleClaims = new List<Claim>()
{
new Claim("role", "readers"),
new Claim("role", "writers"),
};

claims.AddRange(roleClaims);

var token = new JwtSecurityToken(
issuer: _config.GetSection("JwtTokenOptions")["Issuer"],
audience: _config.GetSection("JwtTokenOptions")["Audience"],
claims: claims,
expires: DateTime.Now.Add(TimeSpan.FromSeconds(double.Parse(_config.GetSection("JwtTokenOptions")["Expiration"]))),
signingCredentials: signingCredentials);

var tokenData = new JwtSecurityTokenHandler().WriteToken(token);
return tokenData;
}

Son durumda swagger görüntüsü aşağıdaki gibi olur.

Şimdi JWT üretimini denemek için GetToken metodunu çağıralım.

Gelen token’ı jwt.io da incelediğimizde:

Şimdi ItemsController class tanımının üzerine [Authorize] atribute tanımını ekleyelim. Artık token olmadan doğrudan ItemsController’daki herhangi bir metodu çağırdığımızda 401 Unauthorized hatası alacağız. Amacımız GetToken metodundan token üretip çağırmaktı, yukarıda aldığımız token ile deneyelim. Bunun için swagger sağ üst köşedeki Authorize’a tıklayıp açılan pencereden Value kısmına -> Bearer tokenbilgisiniyapıştırıyoruz.

Ve GetItems metodunu çağırdığımızda:

Sonuçları geliyor. Buraya kadar olan kısımda JWT kütüphanesini ekledik, tanımlarını gördük ve devamında simetrik anahtar kullanan HS256 algoritması ile şifrelenmiş token üretimini gerçekleştirdik ve son olarak denedik. Yazının sonuna doğru kullanım pratiğinde genelde merak edilenlerle devam edeceğim.

Audience Nasıl Çalışıyor?

Tanım dosyamızda yani appsettings.json dosyamızda issuer ve audience tanımlarımız vardı. Issuer, token üreticisinin bilgisini taşırken audience ise token’ın kullanıcısını belirlemekteydi. Örneğin bir token ürettik ve bunun her serviste değil de sadece bazı servislerde kullanılabilmesini istemekteyiz. Bu durumda audience tanımını kullanırız. Somut örnek üzerinden gidelim. Örnek projemizde mevcut tanımlarla token üretelim.

Tanımlar:

 "JwtTokenOptions": {
"Issuer": "AspNetJWT",
"Audience": "ItemsAud",
"SigningKey": "simetrik sifreleme anahtari kullanacagiz",
"Expiration": 3600
}

Üretittiğimiz token:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJldW5hbCIsIm5hbWUiOiJlbmdpbiB1bmFsIiwicm9sZSI6WyJyZWFkZXJzIiwid3JpdGVycyJdLCJleHAiOjE2OTMyMzQ4MjYsImlzcyI6IkFzcE5ldEpXVCIsImF1ZCI6Ikl0ZW1zQXVkIn0.FjQkT5i7EDPQ1_2KsFI7i3YkL9hhB5HKSrnLeCRtwMs

Token içinde aud değeri:
"aud": "ItemsAud"

Bu token ile GetItems servisini çağırdığımızda çalışacaktır. Projeyi kapatıp appsettings.json içindeki Audience değerini “DenemeServis” olarak değiştirelim ve projeyi tekrar başlatalım. Mevcut token’ı Swagger UI’daki Authorize ekranından aşağıdaki gibi girelim ve GetItems servisini çağıralım.

Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJldW5hbCIsIm5hbWUiOiJlbmdpbiB1bmFsIiwicm9sZSI6WyJyZWFkZXJzIiwid3JpdGVycyJdLCJleHAiOjE2OTMyMzQ4MjYsImlzcyI6IkFzcE5ldEpXVCIsImF1ZCI6Ikl0ZW1zQXVkIn0.FjQkT5i7EDPQ1_2KsFI7i3YkL9hhB5HKSrnLeCRtwMs

Aşağıdaki hatayı alırız:

www-authenticate: Bearer error="invalid_token",
error_description="The audience 'ItemsAud' is invalid"

Servisimiz “DenemeServis” aud değerini bekliyor ama token içindeki değer “ItemsAud” olarak geldiğinden bu token bu servis için üretilmemiş ve ValidateAudience kontrolünden geçemiyor. (Not: Biz Program.cs içinde TokenValidationParameters altında ValidateAudience parametresini tanımlamadık bu nedenle default tanımıyla yani ValidateAudience=true olarak çalıştı). Yukarıdaki örnekte tek proje üzerinden anlatmaya çalıştım ama size önerim iki farklı web api projesi oluşturup birbiri ile haberleşmesinde bu parametreleri değiştirerek denemenizdir.

Şimdiye kadar anlatılanlarla ilgili kod örneğini aşağıdaki repo’dan inceleyebilirsiniz.

https://github.com/enginunal/AspNetJWT/tree/webapi-jwt-symmetric-hmac

Asimetrik Anahtar İle JWT Üretimi Nasıl Yapılır?

Simetrik anahtara göre çok daha güvenli bir yöntem olan asimetrik anahtar şifrelemesinin nasıl yapılacağını inceleyelim. Asimetrik şifreleme algoritması olarak PS256 (RSASSA-PSS — SHA-256) kullanacağım. Öncelikle Private/Public Key çiftine ihtiyacımız olacak. Bunu üretip appsettings.json içerisinde aşağıdaki değişikliği yapıyorum. (Not: Private Key en üst düzeyde korunması gereken bir veridir config dosyaları, proje dosyaları, kodlar vb. ortamlarda tutmayınız.)

{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"ConnectionStrings": {
"ItemsConnection": "Data Source=ItemsDb.db"
},
"JwtTokenOptions": {
"Issuer": "AspNetJWT",
"Audience": "ItemsAud",
"Expiration": 10,
"PrivateKey": "MIIEpAIBAAKCAQEA42x8DXg7KuqaIiQVAktrUpSBfnHfNpZBZrVqhk676oF0V9Jo4R9S/ML+t6W6/3jLfYriwmJAUK6i5XihKijYcGsgqbDnk7ymD9sX6JQi+7YviQdNiPPHlbd6ULxwaFRp8VRoeHkJwz7cb1S46I4KXjSDLzg7V9UoILllvfwkw2g5HmukQCwirOPTfJU4X6W0F8Cc6KYWILGMWoL3L965JxXrSBLUAynMw2XiuudWbAirS5H6aVM58QP5bhO884azLCsgTmQr78EHEtY3KuopMR3h607n8UB0SsaBXc+suN/FMFStLlIktej1KpZjPOQYplFVb1Za4qm550W3+vA3uQIDAQABAoIBAAe/tYZb92Ah+Dh7lD+sxC5fIv5k8N8SRY4zVjrXSe3WlVk8sRgikhhMqJMnUXTM79oKNmm7IUfee2xoLM2b8Kv76nP9tBZDkkDuDSV+jqaW8Y2wswKck8tVIhTIJuhXH/j6EEkyjpOZe7dLYrWByXamQWYFe3glqiVbS80qXzJNNVehJZKWE4C0p95zylLeve87z6ESRqEFEGGajg1fJ1y8HiBFLLIeo8PhXVQb+12Lli4nt4J5e26vGftZbEBc2hgHmy+z03lUIwlLjHtnSIMncdVNoDxpIGrk000tan77RMbUtEtoJDrDlT31nUihxghDKCo40M6dWIAn/mYF5QUCgYEA/BLInz+lgE3XLxVjDoTl5oln4d1iLfzmAx/D+AKeIsg+t4wEVFhJ8z35t9+Rgge2+0vdFIXt0cmCxT6xgvDwPB4tzRgihowierGs/LBA3ALChw87Km7ZhmZPNi0N1ZKOOQUpIEUVqquMRBuIPjGhX+/zrV9HD1EYgrhxllxnLbMCgYEA5vdnRFDufdMqYj274GgZBLPdRlmT9m+5fbBDczRzhRJuxwH0enmJ/pswpKtDi/233eLUAUQoFT9ncn/umLsJvpsmknXEjJu5j/+lhy5zMv37Zj0DZiV/tkmrNH2Z3fuVVHC0MRGKee/JQkAjq3498epkfHRgHallSzAlzxLdhuMCgYEAyffK4z29v2WfCkyah6GYCvUBVQlqhupg6RPkkqyWQ8wp5Cq9tU7gQZLgqKDrF0JTLFoGk1ET0ckhjCTFWeLuuVx82h2CXEefwKrnrbcS4LUdY9WiVEdo5rTGtuO2d+7rIWivIPn5eDvnMRLWQO7HG/VISxtR9kXF28coy47R5N0CgYB5IXmsT5G0tcG9wki9WXr9h2NeWO6LyW6L55yIWBLZ0J/+iRzx+roPqM5rHlMPoWID4cl0XI11D0qutz+oJDfpGi+xkkghwi4gwl/KtOa/8IofxZH5yWLgdGRw5AqFbEOWBIHMVjm817BCqabLcysDq/1FdDdQdx3jv/2kS22ZJwKBgQD6ZZc5imJ3R78wJt/PXkYXlqF/pvN83ImwSTGhyyDi+sLdhwqXhxGOoD9MlhR2Cv5bufzxYzsrRvpLt4szu6lE/9b+MjIjCjQqkGVxOcQjlTGuQg8Xd/pkhNePghD0aFKvzVThsNclhntiGkRvroG7eGW19gCWa71o54RzF6I5LQ==",
"PublicKey": "MIIBCgKCAQEA42x8DXg7KuqaIiQVAktrUpSBfnHfNpZBZrVqhk676oF0V9Jo4R9S/ML+t6W6/3jLfYriwmJAUK6i5XihKijYcGsgqbDnk7ymD9sX6JQi+7YviQdNiPPHlbd6ULxwaFRp8VRoeHkJwz7cb1S46I4KXjSDLzg7V9UoILllvfwkw2g5HmukQCwirOPTfJU4X6W0F8Cc6KYWILGMWoL3L965JxXrSBLUAynMw2XiuudWbAirS5H6aVM58QP5bhO884azLCsgTmQr78EHEtY3KuopMR3h607n8UB0SsaBXc+suN/FMFStLlIktej1KpZjPOQYplFVb1Za4qm550W3+vA3uQIDAQAB"
}
}

Program.cs dosyamızda aşağıdaki düzenlemeyi yapıyoruz.

Yukarıdaki değişkliğimiz gelen token’ı doğrulayabilmek için Public Key verisini geçmekten ibaret. Bunu da IssuerSigningKey ile sağlıyoruz. Son olarak TokenController.cs içinde aşağıdaki düzenlemeyi yapıyoruz.

Buradaki düzenleme de çok farklı değil. Token üretirken imzalama için kullanılacak Private Key verisini SigningCredentials’a geçmek gerekiyor bunu sağladık. Şimdi deneyelim. GetToken metodunu çağırdığımızda aşağıdaki gibi imzalı token verisini üretecektir.

eyJhbGciOiJQUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJldW5hbCIsIm5hbWUiOiJlbmdpbiB1bmFsIiwicm9sZSI6WyJyZWFkZXJzIiwid3JpdGVycyJdLCJhdWQiOiJJdGVtc0F1ZCIsImV4cCI6MTY5MzI5ODczMiwiaXNzIjoiQXNwTmV0SldUIiwiaWF0IjoxNjkzMjk4MTMyLCJuYmYiOjE2OTMyOTgxMzJ9.QTKs7obfYKON2NmXsaiuRw3VIg4H5SxU00leTc1SGPgL5F8yyMxSOyPtBq7J-ITDl1mo1SQMQzUcWeikazmwj-qrCmw4kBTZpvpVQIaI2q6fTvjbJor0ORhrvOCv8Cq9IMhRUry2FDeIi240Jwjtq0FNdKQ23uM_UAmp9x0jp5hIfgDkefSpZYqEvydPYubz7e-VbaVrE3j4txXZy-zzf9ACsHsceMTDlzCm95kHuE4cm1i2REVWNoOkuNONDk5fxicEWdww_iENB84s5au62yx28wnpd1jsmcPj0aipiiOY75tkGn5FNkktsnHCztONMK64XWGrZ5KlM7EAoPBkOA

Tekrar çağıralım.

eyJhbGciOiJQUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJldW5hbCIsIm5hbWUiOiJlbmdpbiB1bmFsIiwicm9sZSI6WyJyZWFkZXJzIiwid3JpdGVycyJdLCJhdWQiOiJJdGVtc0F1ZCIsImV4cCI6MTY5MzI5ODc5OSwiaXNzIjoiQXNwTmV0SldUIiwiaWF0IjoxNjkzMjk4MTk5LCJuYmYiOjE2OTMyOTgxOTl9.aRz89LOLmAjx16us2El96zrWt2ZFhDBQSy8MYme35m8v4va0Ke2-0-vY5n1QEQcZ-NpHP5st77U0Y5IUDFroJoObhfiPTtpe5Z34um_QsE8yunbwDWt4jT00M6YTuXyUw3AcXd77COMaiW67-omM4aqdZVAF6BEQ4cxspb2t7ozaBFGHLImtrLHOGkd6wwTV-Y_aKzdGqQTwFtZtn7VnE8CZW9aX_PmruX3gX61T38yWlpjbQG60euGA1m25Zv_uCuYp79rW4jSm_F9HAYYcoxQtAgmOk4TVT1fHsxW_CZYMwiaXE5Y4hdGteJZdI894ZmRpMmHiI7ir16Kq9TX40A

İkincisinde farklı imza üretti.

// ilk token imzası
QTKs7obfYKON2NmXsaiuRw3VIg4H5SxU00leTc1SGPgL5F8yyMxSOyPtBq7J-ITDl1mo1SQMQzUcWeikazmwj-qrCmw4kBTZpvpVQIaI2q6fTvjbJor0ORhrvOCv8Cq9IMhRUry2FDeIi240Jwjtq0FNdKQ23uM_UAmp9x0jp5hIfgDkefSpZYqEvydPYubz7e-VbaVrE3j4txXZy-zzf9ACsHsceMTDlzCm95kHuE4cm1i2REVWNoOkuNONDk5fxicEWdww_iENB84s5au62yx28wnpd1jsmcPj0aipiiOY75tkGn5FNkktsnHCztONMK64XWGrZ5KlM7EAoPBkOA
// ikinci token imzası
aRz89LOLmAjx16us2El96zrWt2ZFhDBQSy8MYme35m8v4va0Ke2-0-vY5n1QEQcZ-NpHP5st77U0Y5IUDFroJoObhfiPTtpe5Z34um_QsE8yunbwDWt4jT00M6YTuXyUw3AcXd77COMaiW67-omM4aqdZVAF6BEQ4cxspb2t7ozaBFGHLImtrLHOGkd6wwTV-Y_aKzdGqQTwFtZtn7VnE8CZW9aX_PmruX3gX61T38yWlpjbQG60euGA1m25Zv_uCuYp79rW4jSm_F9HAYYcoxQtAgmOk4TVT1fHsxW_CZYMwiaXE5Y4hdGteJZdI894ZmRpMmHiI7ir16Kq9TX40A

Kullandığımız algoritma RSASSA-PSS olması nedeniyle imzalanan veri değişmese de imza değişir ve daha güvenli imzalar üretebilir. Bununla ilgili bilgiyi bu yazının başlarında vermiştim. Şimdi token ile GetItems metodunu çağırarak testi bitirelim.

Herşey istediğimiz gibi çalışıyor. Asimetrik anahtar ile imzalama örneği için aşağaki github repo’dan kodları inceleyebilirsiniz.

https://github.com/enginunal/AspNetJWT/tree/webapi-jwt-asymmetric-ps256

Yazının sonuna geldik. Okuduğunuz için teşekkürler.

Engin Ünal

--

--