DEV Community

Hakan Yalitekin
Hakan Yalitekin

Posted on • Originally published at Medium on

.Net Framework için Swagger ve JWT Authentication

Merhaba bu yazıda Swagger ve JWT(JSON Web Token) kavramlarından örnek bir uygulama ile bahsediyor olacağım.

Doğrudan örnek projeyi incelemek için GitHub linki.

Öncelikle kavramlardan kısaca bahsedelim.

Swagger : Rest API geliştirmek için gerekli bir sözleşme standardı ve bu çerçevede işlev gören yardımcı araçlar sunan bir teknolojidir. Swagger sunduğu standart ve araçlarla API tasarım, geliştirme, dokümantasyon ve test aşamasında kolaylık sağlamaktadır.

JWT(JSON Web Token): bir JSON nesnesi olarak taraflar arasında güvenli bir şekilde bilgi iletimi için tasarlanmış bir RFC 7519 standartıdır. JWT, kullanıcının doğrulanması, web servis güvenliği, bilgi güvenliği gibi birçok konuda kullanılabilir.

Neden Swagger’ı ayrı JWT’ı ayrı anlatmadım?

Bunun nedeni servislerde header alanına token eklemeniz gerektiğinde Swagger’da ki ayarlamaları nasıl yapılacağını gösterebilmek. Hazır Swagger’da kullanmak için bir token’a ihtiyacımız varken neden gayet kullanışlı olan JWT den bahsetmeyeyim dedim.

Bir web api projesi oluşturabildiğinizi ya da hali hazırda bir web api projenizin olduğunu varsayıp direk nuget paket’ini indirerek başlıyorum.

Öncelikle token’ımızı oluşturmak için gerekli olan paketi Nudget’tan indiriyoruruz.

Sonrasında JWT token oluşturma ve çözümleme işlemlerini yöneteceğimiz JwtManager.cs adında bir class oluşturuyoruz. İçeriğini aşağıdaki gibi ayarlıyoruz. Ufak detayları açıklama satırları olarak koda ekledim.

using Microsoft.IdentityModel.Tokens;
using System;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
namespace SwaggerWithJWT.Helpers
{
public class JwtManager
{
/// <summary>
/// Simetrik Gizli Anahtar oluşturmak için aşağıdaki kodu kullanılabilir.
/// var hmac = new HMACSHA256();
/// var key = Convert.ToBase64String(hmac.Key);
/// </summary>
private const string Secret = "db3OIsj+BXE9NZDy0t8W3TcNekrF+2d/1sFnWG4HnV8TZY30iTOdtVWJG8abWvB1GlOgJuQZdcF2Luqm/hccMw==";
public static string GenerateToken(string username, int expireMinutes = 240)
{
var symmetricKey = Convert.FromBase64String(Secret);
var tokenHandler = new JwtSecurityTokenHandler();
var now = DateTime.UtcNow;
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new[]
{
new Claim(ClaimTypes.Name, username), //Oturum açan kullanıcı adını ya da maili bu aşamada ekleniyor
new Claim(ClaimTypes.Role, "Role") // İstenirse rol/roller eklenebilir.
}),
Expires = now.AddMinutes(Convert.ToInt32(expireMinutes)),
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(symmetricKey), SecurityAlgorithms.HmacSha256Signature)
};
SecurityToken securityToken = tokenHandler.CreateToken(tokenDescriptor);
var token = tokenHandler.WriteToken(securityToken);
return token;
}
public static ClaimsPrincipal GetPrincipal(string token)
{
try
{
var tokenHandler = new JwtSecurityTokenHandler();
var jwtToken = tokenHandler.ReadToken(token) as JwtSecurityToken;
if (jwtToken == null)
return null;
var symmetricKey = Convert.FromBase64String(Secret);
var validationParameters = new TokenValidationParameters()
{
RequireExpirationTime = true,
ValidateIssuer = false,
ValidateAudience = false,
LifetimeValidator = LifetimeValidator, //Token'nın geçerlilik zamanını kontrol ediyoruz.
IssuerSigningKey = new SymmetricSecurityKey(symmetricKey)
};
var principal = tokenHandler.ValidateToken(token, validationParameters, out _);
return principal;
}
catch (Exception)
{
return null;
}
}
//Token'nın geçerlilik zamanını kontrol ediyoruz.
static bool LifetimeValidator(DateTime? notBefore, DateTime? expires, SecurityToken securityToken, TokenValidationParameters validationParameters)
{
if (expires != null)
{
if (DateTime.UtcNow < expires) return true;
}
return false;
}
}
}
view raw JwtManager.cs hosted with ❤ by GitHub

Artık elimizde token yapımızı yönetebileceğimiz bir token manager sınıfımız olduğuna göre Authentication Attribute’ümüzü yazabiliriz. Öncelikle eğer yoksa Filters adında bir klasör oluşturup içerisine JWTAuthenticationAttribute.cs adında bir klas ekliyoruz ve içeriğini aşağıda ki gibi oluşturuyoruz. Gerekli açıklamaları yorum satırları olarak koda ekledim.

using SwaggerWithJWT.Helpers;
using System.Net;
using System.Net.Http;
using System.Web.Http.Controllers;
using System.Web.Http.Filters;
namespace SwaggerWithJWT.Filters
{
public class JWTAuthenticationAttribute : AuthorizationFilterAttribute
{
//override yazıp ovirrede yapılabilecek metorlar listesinden OnAuthorization'u seçiyoruz.
public override void OnAuthorization(HttpActionContext actionContext)
{
//Gelen request'i kontrol editoruz. Authorization boş ise direk 401 Unauthorized veriyoruz.
if (actionContext.Request.Headers.Authorization == null)
{
actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized);
}
//Eğer doluysa geçerliliğini kontrol ediyoruz.
else
{
var tokenKey = actionContext.Request.Headers.Authorization.Parameter;
var decodeToken = JwtManager.GetPrincipal(tokenKey);
if (decodeToken == null)
{
actionContext.Response = actionContext.Request.CreateResponse(System.Net.HttpStatusCode.Unauthorized);
}
}
}
}
}

Authentication Attribute’ümüzü de yazdığımıza göre kimlik doğrulaması yapacağımız controller’larımıza gerekli eklemeleri yapıyoruz.

İlgili attribute’ü eklediğimize göre artık kimlik doğrulaması isteneceği için token alacağımız bir login metodu oluşturuyorum.

JWT token ile ilgili tüm işlemlerimizi tamamladığımıza göre artık Swagger aşamasına geçebiliriz.

Bunun için Nudget Packege Manager ’a Swashbuckle yazıp aratıyorum (swagger yazarak ta aratabilirsiniz) .Net Core için olanı indirmediğinize emin olun.

Doğru paketi indirdiğinize emin olun.

Swasbuckle paketini indirdikten sonra, metotlarımızın üstüne eklediğimiz summery’lerin swagger’da anlam kazanabilmesi için bazı ayarlamalar yapmamız gerekmekte. Bu ayarlamaları aşağıda açıklamalarıyla anlatmaya çalıştım.

Projemizde bu ayarı yaptıktan sonra, Swasbuckle paketini indirdiğimizde App_Start’ın altına eklenen SwaggerCongfig.cs ’in içerisinde de bazı ayarlamalar yapmamız gerekmekte. Ben beraberinde gelen açıklama satırlarını kaldırdım. Sizde kaldırmadan önce bir göz gezdirebilirseniz faydasını göreceksiniz.

using SwaggerWithJWT;
using Swashbuckle.Application;
using System;
using System.IO;
using System.Reflection;
using System.Web.Http;
using WebActivatorEx;
[assembly: PreApplicationStartMethod(typeof(SwaggerConfig), "Register")]
namespace SwaggerWithJWT
{
public class SwaggerConfig
{
public static void Register()
{
var thisAssembly = typeof(SwaggerConfig).Assembly;
GlobalConfiguration.Configuration
.EnableSwagger(c =>
{
c.SingleApiVersion("v1", "Swagger With JWT (İstenilen herhangi bir isim verilebilir.)");
//Token için eklendi.
c.ApiKey("Authorization")
.Description("Filling bearer token here")
.Name("Bearer")
.In("header");
//Summary için eklendi. //Uyarı mesajlarını kaldırmak için Projenin Proproty'sinde ki Build'in altınada ki warning'e 1591 eklenmelidir.
var baseDirectory = AppDomain.CurrentDomain.BaseDirectory + @"bin\";
var commentsFileName = Assembly.GetExecutingAssembly().GetName().Name + ".XML";
var commentsFile = Path.Combine(baseDirectory, commentsFileName);
c.IncludeXmlComments(commentsFile);
})
.EnableSwaggerUi(c =>
{
//Token için eklendi.
c.EnableApiKeySupport("Authorization", "header");
});
}
}
}

Artık tüm ayarlamalarımızı tamamladığımıza göre ilk testimizi gerçekleştirelim. Ben kolaylık olsun her seferinde linkin sonuna swagger yazmamak için şöyle bir şey yaptım. Bunu yapmadan direk linkin sonuna swagger yazarak swagger’a erişebilirsiniz.

Eğer bu yazı ile ilerlediyseniz görmeniz gereken görüntü şu şekilde olmalı.

Şimdi JWT token yapımızın çalışıp çalışmadığını deneyelim. Öncelikle tokensız deniyorum ve aşağıda görüldüğü üzere 401 unauthorized hatasını alıyorum.

Şimdi ise oturum açıp token ile beraber swagger’ı nasıl kullanacağımıza bakalım. Bunun için öncelikle aşağıda ki gibi oturum açıyorum.

Oluşan token’ın başına Bearer yazdıktan sonra Swagger’ın api key alanına aşağıda ki gibi ekleyip Explorer’a tıklıyorum. (Tırnak işaretlerini almadığınıza emin olunuz.)

Tekrar HomeController altında ki Get’i tetiklediğimiz de Get metodumuzun sorunsuz bir şekilde çalıştığını görebilirsiniz.

Umarım ufakta olsa faydam dokunmuştur.

Kaynaklar;

Postmark Image

Speedy emails, satisfied customers

Are delayed transactional emails costing you user satisfaction? Postmark delivers your emails almost instantly, keeping your customers happy and connected.

Sign up

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay