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.

screenshot_2

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.

screenshot_3

screenshot_4

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.

screenshot_5

 

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.

screenshot_6

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)
        {
        }
    }
}

screenshot_8

 

screenshot_9

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."
}

screenshot_10

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:

screenshot_11

screenshot_12

screenshot_13

{
    "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

screenshot_16

[
    "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  :

screenshot_14

screenshot_15

 

Ö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.

screenshot_17

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 :

Gökhan-Gökalp-Blog

Udemy – ASP.NET WEB API ile Yazılımcıların Bağımsızlığı

 

 

 

 

Print Friendly, PDF & Email

You may also like...

1 Response

  1. Eser TOPÇU dedi ki:

    Çok faydalı bir yazı olmuş. Emeğinize sağlık…

Bir cevap yazın