Asp.Net Web API – Bearer Token Authentication- Token Based Authentication
Merhabalar ,
Bu yazımda Bearer Token Authentication- Token Based Authentication web api mizde nasıl uygulayacağımızı adım adım anlatacağım.
Proje Kodları GitHub : https://github.com/salihseker/ASP.NET-WEB-API-OAuth-2.0-Token-Based-Authentication-Bearer-Token
Bearer Token Authentication – Wep Api Projesi geliştirmesi ve ayarlamaları :
Öncelik olarak bir Asp.Net Web Api projesi oluşturuyoruz. Örneğimizde Authentication işlemleri için OAuth 2.0 protokolü ile sağlayacağız . bunun için Microsoft’un Owin kütüphanesinden yararlanacağız. Owin Kütüphanesini projemize eklemek için Nuget arama kısmında Owin yazıp çıkan sonuçlar içerisinde :
- Microsoft.AspNet.WebApi.Owin
- Microsoft.Owin.Host.SystemWeb
- Microsoft.Owin.Security.OAuth
seçerek projemize kuruyoruz.
Projemiz çalıştırıldığında , projemize nuget tan eklediğimiz Owin pipeline i ayağı kaldırmak ve gerekli ayarlamaları yapmamız için projemize bir Startup.cs dosyası eklememiz gerekiyor.
düzenli olması açısından OAuth adında bir klasör oluşturup içerisine Startup.cs dosyamızı oluşturuyoruz , Startup.cs dosyamızı oluştururken , Add kısmından startup olarak arattırıp owin startup seçeneğini seçmeliyiz.
Startup.cs : ilk hali .
using System; using System.Threading.Tasks; using Microsoft.Owin; using Owin; [assembly: OwinStartup(typeof(WebApiBearerTokenApp.OAuth.Startup))] namespace WebApiBearerTokenApp.OAuth { public class Startup { public void Configuration(IAppBuilder app) { // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=316888 } } }
Startup ayarlamalarımızı yapmadan önce startup ayarlarında kullanacağımız Provider (sağlayıcı) nesnemizi oluşturalım.
OAuth kasörü altına Providers adında bir kalsör açarak içerisine AuthorizationServerProvider.cs adında bir sınıf ekledik, sonrasında OAuthAuthorizationServerProvider sınıfını miras alıyorum.
AuthorizationServerProvider.cs :
using Microsoft.Owin.Security.OAuth; using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Threading.Tasks; using System.Security.Claims; namespace WebApiBearerTokenApp.OAuth { public class AuthorizationServerProvider : OAuthAuthorizationServerProvider { public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context) { // OAuthAuthorizationServerProvider sınıfının client erişimine izin verebilmek için ilgili ValidateClientAuthentication metotunu override ediyoruz. context.Validated(); } // OAuthAuthorizationServerProvider sınıfının kaynak erişimine izin verebilmek için ilgili GrantResourceOwnerCredentials metotunu override ediyoruz. public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context) { // CORS ayarlarını set ediyoruz. -- Cross Domain yazım dan konu ile alakalı detaylı bilgi alabilirsiniz. context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" }); //validation işlemlerini ve kontrollerini bu kısımda yapıyoruz , örnek olması için sabit değerler verildi , //bu kısmı db den okuyacak şekilde bir yapı kurgulanabilir. if (context.UserName.Equals("salihseker", StringComparison.OrdinalIgnoreCase) && context.Password == "123456") { //eğer başarılı ise ClaimsIdentity (Kimlik oluşturuyoruz) var identity = new ClaimsIdentity(context.Options.AuthenticationType); identity.AddClaim(new Claim("sub", context.UserName));//Identity özelliklerini ekliyoruz. identity.AddClaim(new Claim("role", "admin")); context.Validated(identity);//Doğrulanmış olan kimliği context e ekliyoruz. } else { //eğer hata var ise bir hata mesajı gönderiyoruz. hata ve açıklaması şeklinde. context.SetError("Oturum Hatası", "Kullanıcı adı ve şifre hatalıdır"); } } } }
AuthorizationServerProvider sınıfının iki metodu ovverride ettik.
- ValidateClientAuthentication: Client’ı doğrulamak için ki direkt olarak doğruladık biz.
- GrantResourceOwnerCredentials: asıl kaynak erişimine verilecek yetkilerin ayarlandığı ana kısım. CORS ayarlarını gerçekleştirdik. ve kullanıcı adı parola validationu gerçekleştirdik eğer başarılı bir giriş sağlanır ise bir kimlik (identity) oluşlturduk , hata var ise hata mesajımızı yazdık. kimlik doğrulama kısmı şu anlık sabit , bu yapıyı projenize göre veritabanından okuyacak şekilde düzenleyebilirsiniz.
OAuthAuthorizationServerProvider sınıfından implement ettiğimiz provider nesnemiz hazır olduğuna göre bunu kullanacağımız startup.cs dosyamızı kodlamalarını yapabiliriz.
Startup.cs :
using System; using System.Threading.Tasks; using Microsoft.Owin; using Owin; using Microsoft.Owin.Security.OAuth; using System.Web.Http; [assembly: OwinStartup(typeof(WebApiBearerTokenApp.OAuth.Startup))] namespace WebApiBearerTokenApp.OAuth { public class Startup { public void Configuration(IAppBuilder app) { HttpConfiguration configuration = new HttpConfiguration(); Configure(app); WebApiConfig.Register(configuration); app.UseWebApi(configuration); } private void Configure(IAppBuilder app) { OAuthAuthorizationServerOptions options = new OAuthAuthorizationServerOptions() { TokenEndpointPath = new Microsoft.Owin.PathString("/token"),// token alacağımız path'i belirtiyoruz AccessTokenExpireTimeSpan = TimeSpan.FromHours(1),//token expire süresini ayarlıyoruz Örn : 1 saat AllowInsecureHttp = true, Provider = new AuthorizationServerProvider() }; app.UseOAuthAuthorizationServer(options); //IAppBuilder e hazırlamış olduğumzu Authorization ayarlarımızı veriyoruz. app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());// Authentication type olarak Bearer Authentication'ı kullanacağımızı belirtiyoruz. } } }
Configure metodumuzda oturum açma ile ilgili gerekli ayarlamalalarımız tanımladık.
options nesnemizideki ayarlara kısaca değinirsek
- TokenEndpointPath : token isteği yapacağımız url örn: sitaadi/token
- AccessTokenExpireTimeSpan : token ın geçerlilik süresi ayarı
- AllowInsecureHttp : http siteklere izin verilmesi
- Provider : sağlayıcı ayarlarımız yani owin implementasyonu yapmış olduğumuz ve validation işlemlerinin bulunduğu sınıfımızı tanımladık : AuthorizationServerProvider
Sonrasında UseOAuthAuthorizationServer ile IAppBuilder e hazırlamış olduğumz Authorization ayarlarımızı veriyoruz.
ve en sonunda app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions()); ile Authentication type olarak Bearer Authentication’ı kullanacağımızı belirtiyoruz.
Bearer Token için gerekli olan ayarlamalar , kodlamalar ve tanımlamalar (Owin için OAuth 2.0 implementasyonunu)tamamlandı , şimdi bu token ı ve web apimizi nasıl kullanacağımızı , test edeceğimizi görelim.
Öncelik olarak data çekeceğmiz controller içerisinde kimlik doğrulaması yapılmasının zorunlu olması için [Authorize] attributunu ekliyoruz.
Projemde bulunan ValuesController ın üzerine [Authorize] ekliyorum ki içerğinde bulunan tüm action lar için geçerli olsun.
ValuesController.cs :
using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Http; using System.Web.Http; namespace WebApiBearerTokenApp.Controllers { [Authorize] public class ValuesController : ApiController { // GET api/values public IEnumerable<string> Get() { return new string[] { "value1", "value2" }; } // GET api/values/5 public string Get(int id) { return "value"; } // POST api/values public void Post([FromBody]string value) { } // PUT api/values/5 public void Put(int id, [FromBody]string value) { } // DELETE api/values/5 public void Delete(int id) { } } }
kodlamalarım tamamlandığı için artık projemi çalıştırıp Postman tool u ile testlerimizi gerçekleştirelim.
Postman yerine Fiddler tool unu tercih edebilirsiniz , tamamen sizin tercihiniz.
Test işlemleri :
Projemin şu an herhangi bir sunucuya host edilmediği için kendi lokalimde visual studio yardımı ile derlenip ayağı kaldırılacak , projemin çalıştığında oluşan url bilgisini görüntülemek isterseniz .
proje ye sağ tıklayıp properties sayfasından web sekmesinde bulunan project url kısmından görüntüleyebilirisiniz.
herhangi bir authorization işlemi yapmadan api methoduna istek atıyorum , maksa herhangi bir hata alıp almayacağımı kontrol etmek
api linki : http://localhost:60429/api/Values istek methotu GET
ve dönen hata
{ "Message": "Authorization has been denied for this request." }
başarılı bir şekilde request atmak için öncelik olarak /token path’i ile belirttiğimiz adrese gidip geçerli bir access_token almalıyız.
Bunun için POST tipinde bir istek atmalıyız tabi öncelik olarak Header ve Body parametre bilgilerini girmeliyiz :
Url : http://localhost:60429/token
Method : POST
Header :
Key : Accept Value : application/json
Key : Content-Type Value :application/x-www-form-urlencoded
Body:
Key: grant_type Value: password
Key: username Value: salihseker (Kullanıcı adınız)
Key: password Value: 123456 (Şifreniz)
data tipi x-www-form-urlencoded olarak seçilmeli.
POST işlemini gerçekleştirelim ve gelen sonuca bakalım:
{ "access_token": "wkJyTWmaNFIQ7dJzokoEdPo9ZWdpwhj0lGVuSYo0R-yFseYNizPA_r5rGtOazVrFOKA5W4klDzZEqqV14A9P7W38Rps-8FwsX2YIo64_hGUXlUbNnv9Tuiz7gvuyJ3fcNAh028UtlGyiI_nQFB9Mt-73XNPVXEiZJO6bhNNbCfnu-PugEy5GXVSGA7sA4iDJ3PojZzj0XB3cGPJ-eYjhx96o9Z4hsvkFQNqRNqWeCBE", "token_type": "bearer", "expires_in": 3599 }
dönen JSON sonucunda access_token oluşmuş ve expires_in süresi ile geldiğini görüyoruz. Bu süreyi Startup.cs dosyasında Configurasyon bölümünde AccessTokenExpireTimeSpan propertysi ile vermiştik.
artık bu token ı kullanarak apimizdeki http://localhost:60429/api/Values controllerımıza istek atıp başarılı bir sonuç alalım.
Url : http://localhost:60429/api/Values
Method : GET
Header :
Key : Content-Type Value :application/x-www-form-urlencoded
Key : Authorization Value : Bearer wkJyTWmaNFIQ7dJzokoEdPo9ZWdpwhj0lGVuSYo0R-yFseYNizPA_r5rGtOazVrFOKA5W4klDzZEqqV14A9P7W38Rps-8FwsX2YIo64_hGUXlUbNnv9Tuiz7gvuyJ3fcNAh028UtlGyiI_nQFB9Mt-73XNPVXEiZJO6bhNNbCfnu-PugEy5GXVSGA7sA4iDJ3PojZzj0XB3cGPJ-eYjhx96o9Z4hsvkFQNqRNqWeCBE
[ "value1", "value2" ]
Web Apimizden başarılı şekilde verilerimizi çekiyoruz.
Postman de yaptığımız işlemleri kod tarafında kullanmak için Postman in sağlamış oluğu Code kısmından örnek request i alıp istediğimiz şekilde düzenleyebiliriz.
Örn C# tarafında sıkça kullanılan RestSharp dll i (nuget tan projenize ekleyip kullanabilirsiniz) için code çıktısı veya örnek ajax istek çıkdıtısı alabilirsiniz :
Örnek Ekran Görüntüleri :
Örnek: AJAX kodu ile Bearer Token Kullanımı :
Token alma işlemi :
<script> function Login() { var loginObject = { userName: $("#userName").val(), password: $("#password").val(), grant_type: "password", }; $.post("http://localhost:60429/token", loginObject, function (result) { sessionStorage.removeItem("MyToken"); sessionStorage.setItem("MyToken", result.access_token); window.location.href = window.location.href.replace("Login", "Home"); }).fail(function (err) { alert(err.status + " " + err.statusText); }); } </script>
sayfamızda userName , password id lerine sahip textbox larımız olsun bu alanalara kullanıcı adı ve şifremiiz giriyoruz : örn salihseker , 123456 şeklinde grant_type = “password” olarak set ediyoruz ve userName , password, grant_type bilgilernin bulunduğu bir loginObject adında obje oluşturuyoruz , Ajax $post ile token url imize loginObject mizi gönderdiğimizde obje olduğu için body kısmına alacaktır , sonrasında yapılan istek başarılı ise dönen json datası yani function (result) taki result nesnesindeki access_token bilgisi bizim token ımız.
bu bilgi kaybolmaması için session Storage e MyToken adı ile kaydediyoruz, daha sonra okurken token bilgisini bu kısımdan okuyacağız .
Session Storage verilireni görüntülemek için Chrome da F12 ile Application sekemsinden Session Storage kısmından inceleyebilirsiniz.
alınan tokın ın kullanılması :
<script> function SendRequest(type, url, token, callbackFunction, data) { $.ajax({ type: type, url: url, dataType: "json", data: data, headers: { Authorization: "Bearer " + token }, success: function (response) { callbackFunction(response); }, error: function (err) { alert(err.status + " " + err.statusText); } }); } var url = "http://localhost:60429/api"; function GetOturum() { SendRequest("GET", url + "/Authorization", sessionStorage.getItem("MyToken"), function (response) { var text = "Kullanıcı: " + response.UserName + "<br/> Rol: " + response.Role + "<br/> Dil: " + response.Lang; $("#tdOturum").html(text); }); } function GetKategori() { SendRequest("GET", url + "/Cotegory", sessionStorage.getItem("MyToken"), function (response) { console.log("kategor", response); $(response).each(function (index, value) { $("#slKategori").append("<li>" + value.Name + "</li>"); }); }); } function logout() { sessionStorage.removeItem("MyToken"); } </script>
Şeklinde kullanılabilir.
Proje Kodları GitHub : https://github.com/salihseker/ASP.NET-WEB-API-OAuth-2.0-Token-Based-Authentication-Bearer-Token
Umarım faydalı olmuştur .
İyi Çalışmalar – Salih ŞEKER
Kaynak :
Udemy – ASP.NET WEB API ile Yazılımcıların Bağımsızlığı
Çok faydalı bir yazı olmuş. Emeğinize sağlık…