Merhaba arkadaşlar, bu makalemde Asp.Net Web API ile RESTful servis geliştirirken Token Based bir Authentication işlemi nasıl yapıldığına dair örnek bir proje yapacağız.
RESTful’ün önemini kısaca hatırlamak gerekirse:
- Fazlasıyla basit ve esneklik sağlamaktadır.
- REST’in HTTP protokolü üzerine kurulmuş olmasıyla beraber günümüz modern web dünyasındaki bir çok uygulamalar kendini browser tabanlı uygulamalara bırakıyor ve artık bir çok işlem client-side tabanlı yapıldığı için REST servisleri bize bir artı daha sağlıyor bu anlamda.
Özünde RESTful servisleri bize client-server arasındaki yapacak olduğumuz veri transferini SOAP veya RPC gibi kompleks mimariler yerine daha hafif ve esnek bir şekilde yapabilme olanağı sağlıyor.
REST mimarisini hatırladığımıza göre, gelelim şimdi nedir bu Token Based Authentication?
Günümüz çağında geliştirilen neredeyse tüm uygulamaların bir mobil bacağı bulunmaktadır veya mobil tarafına da destek verebilecek şekilde servis mimarileri geliştirilmektedir. REST mimarisi üzerine kurulan bir serviste ise güvenlik işlemlerini ele alabilmek, client’ı yetkilendirebilmek için Token (Jeton) bazlı bir yetkilendirme işlemi yapılmaktadır.
Token Based Authentication işleminin yaşam döngüsüne bakmak istediğimizde ise:
- Client kendi güvenlik bilgilerini girer ve bu bilgiler Authorization Server‘a gönderilir
- Authorization Server bu bilgileri doğrulursa, client’a bir Access Token Http Response’u döner.
- Client artık erişmek istediği servislere, elde etmiş olduğu Access Token’ı Http Request’in Authorization Header‘ına ekleyerek erişim sağlar.
Bu ön bilgilerden sonra hemen örneğimize geçelim. Öncelikle örneğimizde Authentication işlemleri için OAuth 2.0 protokolü ile sağlayacağız ve bunun için Microsoft’un Owin kütüphanesinden yararlanacağız.
Owin temelinde IIS ile Application arasında kendi pipeline’ını kuruyor ve işlemleri burada handle ediyor. Lightweight bir pipeline’a sahiptir.
AspNetWebAPIOAuth isminde bir Asp.Net Web Application oluşturuyorum. Oluştururken Template kısmından Empty seçip Core Referansını ise Web API seçerek tamamlıyorum.
Projemizi oluşturduğumuza göre hemen projemiz üzerine sağ tıklayarak NuGet Package Manager’ı açıp Search kısmından OAuth yazarak çıkacak olan sonuçlar içinden Microsoft.AspNet.WebApi.Owin, Microsoft.Owin.Host.SystemWeb ve Microsoft.Owin.Security.OAuth‘u seçerek projemize kuruyoruz.
Proje içerisine OAuth isimli bir klasör ekleyerek servis çalışmaya başlarken Owin pipeline’ını ayağa kaldırabilmek için Startup sınıfını hazırlamaya başlıyoruz ve içerisinde gerekli konfigürasyon ayarlarını WebApiConfig‘e register edip, Owin Server üzerinde uygulama oluşurken kullanacağı konfigürasyon ayarınıda belirtiyoruz.
Startup.cs:
using AspNetWebAPIOAuth.OAuth.Providers; using Microsoft.Owin; using Microsoft.Owin.Security.OAuth; using Owin; using System; using System.Web.Http; [assembly: OwinStartup(typeof(AspNetWebAPIOAuth.OAuth.Startup))] namespace AspNetWebAPIOAuth.OAuth { // Servis çalışmaya başlarken Owin pipeline'ını ayağa kaldırabilmek için Startup'u hazırlıyoruz. public class Startup { public void Configuration(IAppBuilder appBuilder) { HttpConfiguration httpConfiguration = new HttpConfiguration(); ConfigureOAuth(appBuilder); WebApiConfig.Register(httpConfiguration); appBuilder.UseWebApi(httpConfiguration); } private void ConfigureOAuth(IAppBuilder appBuilder) { OAuthAuthorizationServerOptions oAuthAuthorizationServerOptions = new OAuthAuthorizationServerOptions() { TokenEndpointPath = new Microsoft.Owin.PathString("/token"), // token alacağımız path'i belirtiyoruz AccessTokenExpireTimeSpan = TimeSpan.FromDays(1), AllowInsecureHttp = true, Provider = new SimpleAuthorizationServerProvider() }; // AppBuilder'a token üretimini gerçekleştirebilmek için ilgili authorization ayarlarımızı veriyoruz. appBuilder.UseOAuthAuthorizationServer(oAuthAuthorizationServerOptions); // Authentication type olarak ise Bearer Authentication'ı kullanacağımızı belirtiyoruz. // Bearer token OAuth 2.0 ile gelen standartlaşmış token türüdür. // Herhangi kriptolu bir veriye ihtiyaç duymadan client tarafından token isteğinde bulunulur ve server belirli bir expire date'e sahip bir access_token üretir. // Bearer token üzerinde güvenlik SSL'e dayanır. // Bir diğer tip ise MAC token'dır. OAuth 1.0 versiyonunda kullanılıyor, hem client'a, hemde server tarafına implementasyonlardan dolayı ek maliyet çıkartmaktadır. Bu maliyetin yanı sıra ise Bearer token'a göre kaynak alış verişinin biraz daha güvenli olduğu söyleniyor çünkü client her request'inde veriyi hmac ile imzalayıp verileri kriptolu bir şekilde göndermeleri gerektiği için. appBuilder.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions()); } } }
Owin ayarlarını başlangıçta içeren sınıfımızı oluşturduk. Sınıf satırlarındaki yorumlarda da belirttiğimiz üzere, Authentication type olarak Bearer Authentication kullanacağız. Sebebi ise daha fazla lightweight olup OAuth 2.0 ile standart bir hale gelmesi ve hem client hemde server side için authentication işlemlerini daha fazla kolaylaştırmasıdır. Ayrıca tüm işlemler her ne kadar bir access token üzerinden yürüyecek olsada, SSL ile client ile server arasındaki veri güvenliği sağlanmalıdır.
OAuthAuthorizationServerOptions ayarlarını tanımlarken Provider olarak OAuthAuthorizationServerProvider sınıfından miras alarak türeteceğimiz SimpleAuthorizationServerProvider ‘ı seçtik. Şimdi gelelim bu provider’ın kodlarını incelemeye. Öncesinde daha önce açtığımız OAuth klasörünün içine hemen bir Providers isminde klasör daha açarak içerisinde ilgili sınıfımızı oluşturuyoruz.
SimpleAuthorizationServerProvider.cs:
using Microsoft.Owin.Security.OAuth; using System.Threading.Tasks; using System.Security.Claims; namespace AspNetWebAPIOAuth.OAuth.Providers { public class SimpleAuthorizationServerProvider : OAuthAuthorizationServerProvider { // OAuthAuthorizationServerProvider sınıfının client erişimine izin verebilmek için ilgili ValidateClientAuthentication metotunu override ediyoruz. public override async System.Threading.Tasks.Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context) { 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. context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" }); // Kullanıcının access_token alabilmesi için gerekli validation işlemlerini yapıyoruz. if (context.UserName == "Gokhan" && context.Password == "123456") { var identity = new ClaimsIdentity(context.Options.AuthenticationType); identity.AddClaim(new Claim("sub", context.UserName)); identity.AddClaim(new Claim("role", "user")); context.Validated(identity); } else { context.SetError("invalid_grant", "Kullanıcı adı veya şifre yanlış."); } } } }
OAuthAuthorizationServerProvider sınıfının iki metodunu ezdiğimizi görüyoruz. Bunlardan birincisi, Client’ı doğrulamak için ki direkt olarak doğruladık biz. İkincisi ise asıl kaynak erişimine verilecek yetkilerin ayarlandığı ana kısım. Öncelikle burada CORS ayarlarını gerçekeleştirdik. Hemen CORS nedir hatırlatması yapmak gerekirse:
CORS domain’ler arası kaynak paylaşımını sağlamaya yarayan bir mekanizmadır. Bir domain’in bir başka domain’in kaynağını kullanabilmesini sağlar.
Hızlıca CORS’u da tekrardan hatırladığımız üzere devamında koda baktığımızda da net bir şekilde görüldüğü gibi validation işlemlerini gerçekleştiriyoruz. Eğer kullanıcı geçerli bir kullanıcı ise bir kimlik yaratıp, context üzerinde doğruluyor.
Evet şuan Owin için OAuth 2.0 implementasyonunu gerçekleştirmiş bulunuyoruz. Şimdi gelelim Controller üzerinde ki kullanımına. Hemen Controllers kısmına OrdersController ekliyorum ve içine List isminde bir metot tanımlıyorum. Form Authentication’dan da hatırlayabileceğiniz üzere metotların üstüne attirbute olarak [Authorize] attributunu ekliyorduk, Owin içinde aynı attribut’u kullanıyoruz.
OrdersController.cs:
using System.Collections.Generic; using System.Web.Http; namespace AspNetWebAPIOAuth.Controllers { public class OrdersController : ApiController { [HttpGet] [Authorize] public List<string> List() { List<string> orders = new List<string>(); orders.Add("Elma"); orders.Add("Armut"); orders.Add("Erik"); return orders; } } }
Api tarafında herşey hazır olduğuna göre projemizi test edebiliriz. Ben tool olarak Postman’ı tercih ediyorum siz isterseniz Fiddler Composer’da kullanabilirsiniz. Postman data gönderirken bana daha fazla esneklik sağlıyor açıkcası. 🙂
Öncelikle direkt olarak ilgili api metodumuza erişmeye çalıştığımızda alacağımız sonuca bir bakalım:
api/Orders/List url’i ile GET isteği attığımızda Authorization hatası aldığımızı görüyoruz. Öncelikle /token path’i ile belirttiğimiz adrese gidip geçerli bir access_token almalıyız.
Bunun için POST tipinde /token url’ine Headers’a ve Body’e bir kaç parametre set ederek gitmemiz gerekmektedir.
Headers’e eklenecek parametreler:
Header: Accept Value: application/json
Header: Content-Type Value: application/x-www-form-urlencoded
Body’e eklenecek parametreler:
data tipi x-www-form-urlencoded olarak seçilip,
Key: grant_type Value: password
Key: username Value: Gokhan (Kullanıcı adınız)
Key: password Value: 123456 (Şifreniz)
İlgili bilgileri girdikten sonra POST işlemini gerçekleştirelim ve gelen sonuca bakalım:
Geriye dönen JSON sorgusunda access_token oluşmuş ve expires_in süresi ile geldiğini görüyoruz. Bu süreyi hatırlarsak Startup kısmında konfigürasyon bölümünde AccessTokenExpireTimeSpan propertysi ile vermiştik.
Artık bu token’ı kullanarak tekrardan api/Orders/List url’ine tekrardan bir GET sorgusunda bulunalım. Fakat bu sefer ilgili token’ı Header’a ekleyerek gönderiyoruz.
Headers’e eklenecek parametreler:
Header: Content-Type Value: application/json
Header: Authorization Value: Bearer jyMJNFpYdBOZxoUZsutu7vNe4JY–kdvdjTylrJi_rZPC5VUOFSTvej-Sq0jvCj1gYbg0HHAk6ILoj0U7G3zCYcl1lK9tA6YwMGODccsorhjwDTzuuGprU00f5j4Ly1DUhS54TejbrZtn1RMegSCXFfixjkYkeXeVd6eP0eGGrAr6f3ICVGz7KASR28soQEh_4sXpOZLmDpDJFKKAEoI_q0h9_7qvfIIjm8t0lDcCp4
Token tipimiz Bearer olduğu için headerda Authorization kısmının değerine access_token’ı girmeden önce Bearer tag’ini ekleyip daha sonrasında access_token’ı ekliyoruz.
Servisten başarıyla bilgileri çektiğimizi görüyoruz. Bir sonraki Web API konumda ise Custom Token Based Authentication işlemi nasıl gerçekleştirilebilir hakkında bir şeyler yazmayı planlıyorum. Şimdilik sağlıcakla kalın.
Emeğine sağlık çok faydalı oldu
Teşekkür ederim.
Makale çok güzel, ellerinize sağlık. Benim bir sorum olacak, postman’la değil de js ile bu işlemleri yapmak istediğimde;
OPTIONS http://localhost:49516/Api/Students 405 (Method Not Allowed)jQuery.ajaxTransport.options.send @ jquery.js:9664jQuery.extend.ajax @ jquery.js:9215(anonymous function) @ app.js:32
index.html:1 XMLHttpRequest cannot load http://localhost:49516/Api/Students. Response for preflight has invalid HTTP status code 405
hatası alıyorum. Token alıp headers kısmından yolluyorum.
Merhaba, CORS ayarlarını yaptınız mı?
Güzel ve anlaşılır olmuş. Anlatımına sağlık
Yazı için teşekkürler. Postman kullanmadan nasıl ajax isteği gönderebileceğimizi anlatabilir misiniz?
Merhaba, kusura bakmayın geç yanıt için yoğunluktan bakamıyorum bu aralar.
Aşağıdaki gibi bir ajax isteği ile access token’ı alabilirsiniz.
< script type="text/javascript">
function GetToken() {
$.ajax({
type: ‘POST’,
url: ‘/Token’,
dataType: ‘json’,
data: { “grant_type”: “password”, “username”: “Gokhan”, “password”: “123456” },
success: function (response) {
// Access token’ı bu şekilde alabilirsiniz.
alert(response.access_token)
}
});
}
< /script>
Merhabalar,
Öncelikle paylaşımınız için teşekkürler.
grant_type alanını authorization_code olarak geçtiğimde invalid_grant hatası alıyorum. Bu hatayı düzeltmek için neler yapabilirim?
Merhaba, grant_type alanını password olarak geçmeniz gerekmektedir.
Merhaba hocam, token request ile dönen JSON nesnesi (access_token, token_type, expires_in) parametrelerini döndürmektedir. Eğer kullanıcı adı ve rollerini de (access_token, token_type, expires_in, username) almak istiyorsak ne yapmalıyız. token bilgisinin yanında username gelsin istiyorsak bunu kodda nereye eklemeliyiz?
Merhaba
client o token bilgileri ile server’a bir request isteği bulunduğunda, eğer token bilgisi geçerli bir token ise SimpleAuthorizationServerProvider class’ının içerisinde kullanıcı bazlı identity oluşturarak “identity.AddClaim(new Claim(“sub”, context.UserName));” satırı ile istediğimiz property’lerini doldurmuştuk. Bu bilgilere server tarafında kullanıcı authentication işleminden geçirildikten sonra ulaşabilirsin. Bu bilgilere ulaşabilmek için ise, System.Web.Http namespace’i altında bulunan User context’i üzerinden ulaşabilirsin. Saygılar.
Merhabalar,
Oldukça temiz bir iş, ellerinize sağlık. Custom Token Auth dan önce Refresh token konusuna da basit bir örnekle değinirseniz çok daha faydalı olacağı konusundayım. Lakin neden ihtiyaç duyulduğu konusunda bazı durumlarda ikilemde kalıyorum.
Replace(parent.comment,”olacağı konusundayım.”,”olacağı kanısındayım.”);
Merhaba, teşekkür ederim öncelikle. Dürüst olmak gerekirse bu konulara daha derinlemesine Şubat ayı gibi çıkacak olan Asp.NET Web API kitabımda değiniyorum. O yüzden şimdilik daha fazla makale ekleyemiyorum bu konuda. Kısaca ihtiyaç duyulma sebebine değinecek olursak: Eğer belirli bir expire süresine sahipse token fakat API’ı consume eden client hala session’a ihtiyacı varsa, tekrardan login olma ihtiyacı yerine refresh token ile yeni bir authorization token isteğinde bulunarak gerçekleştirebilir. Bu sayede client username ve password gibi bilgileri token lifecycle’ı boyunca tekrardan taşımasına ve validation yapmasına gerek yoktur.
Saygılarımla.
Merhabalar;
Piyasaya çıkacak olan kitabınız için şimdiden başarılar diliyorum.Cevabınız için de çok teşekkürler, çok fazla olmuyorsam tam da takıldığım kısım işte burası; Sizin örneğinizde; Bir kullanıcı için, giriş yaptığı sayı kadar (teoride sonsuz) 24 saat geçerli tokenlar üretiyor;
1) Bu bir güvenlik sıkıntısı doğurmaz mı?
– Sonuçta servise erişmek için, bir kullanıcının birden fazla token ı olabiliyor. Geçmişe dönük oluşturulmuş tüm tokenları geçersiz kılacak bir yöntem daha mantıklı değil mi? Mesela kullanıcı yeni bir validasyon yaptığında. Ayrıca en önemli problem; Kullanıcı giriş yaptı, 24 saatlik token üretildi, sonra kullanıcı şifresini değişti, ancak üretilen tokenı kullanan ile diğer uygulamalar hala daha kaynaklara erişebilir durumda çünkü token 24 saat geçerli.(içerde her authorize durumunda fazladan bir kontrol yapmıyorsan)
2) Refresh token ile sürekli kullanıcıdan giriş yapmasını önleyerek kullanıcı bilgilerini güvene alabiliyoruz.
– Çok iyi de, ben servis sunucusu olarak piyasaya geçerli bir token sunduğumda, uygulama o token ı sürekli refresh ile uzatıp, süresiz olarak kullanıcı kaynaklarına erişim sağlayabilir. Kullanıcı istediği kadar şifresini değiştirsin. (içerde her authorize durumunda fazladan bir kontrol yapmıyorsan)
Yada ben bu TOKEN olayını yanlış mı anlıyorum.
Merhaba tekrardan, İlk olarak 24 saat olayını olması gereken expire süresi olacak şekilde algılamayın. Bu sadece bir örnek olduğu için o şekilde verdim. 🙂 Sonuçta bu PoC (proof-of-concept)’deki amacım; custom olarak bir token provider nasıl oluşturulur idi. Dediğiniz gibi güvenlik bacağı ise ayrı bir kısımdır. Gerek login aşamasında gerekse de access_token’ın lifecycle’ı boyunca sağlanacak olan. Öte yandan refresh_token’da bir expire süresine sahiptir. Expire süresi boyunca belirlenen expire dahilinde yeni bir access_token alabilir client. Amaçta budur zaten. Refresh_token expire olduğunda ise tekrardan login olup yeni bir access_token alması gerekmektedir.
İyi günler dilerim.
Merhaba,
Öncelikle anlatımınız için teşekkürler.
Sormak istediğim şu; OAuth ile HttpPost attribute’una sahip metodları Authorize edebiliyor muyuz? Bununla ilgili açıklayıcı bir kaynak bulamadım. Cevaplarsanız memnun olurum.
Merhaba, POST veya GET farketmez, Authorize işlemlerini gerçekleştirebilirsiniz.
Denemelerimde Authrorize ve HttpPost’u birlikte kullandığımda action’a ulaşamıyorum. Bununla ilgili küçük bir örnek paylaşabilir misiniz?
Merhaba token uygulamasını birden fazla sunucuda çalıştırdığım taktirde. A sunucusunda aldığı tokenı B sunucusunda nasıl doğrulatabilirim.
Merhaba. Bu işlem gerçekleştirebilmek için config’ler içerisine machine key’lerin aynı olarak belirlenmesi gerekmektedir. Yani hem token api üzerinde hemde api’ı kullanacak olan uygulama üzerindeki config’ler, aynı machine keylere sahip olmalıdır. Decription işlemleri için machine key içerisinde bulunan “validationKey” ve “decryptionKey” node’ları kullanılmaktadır. Saygılarımla.
Peki ben token sahibinin bilgilerine api tarafında nasıl ulaşabilirim.
Yalnızca token geldi ve method çalıştırmam isteniyor bunu kimin yaptığını loglamak istiyorum.
Tanımlamış olduğun identity’lere api tarafına ilgili token’la gelip valide olduğu zaman, System.Web.Http namespace’i altında bulunan User context’i üzerinden ulaşabilirsin.
Makaleniz çok yararlı, bunun için teşekkürler. Benim sorum şu: controller veya action bazında grant işlemini nasıl gerçekleştirebiliriz? Mesela haberleri listeleme metodunu kullanabilsin ama haber ekle metodunu kullanamasın. Kullanıcı grubu bazında bu durumu nasıl gerçekleştirebilirim?
Merhaba, bu işlemi yapabilmek için client’ı authorize ettikten sonra yeni bir claim eklerken ‘identity.AddClaim(new Claim(“role”, “user”));’ burada istediğiniz custom “role” leri ekleyerek bu “role” değerlerine göre action bazında işlem yapılabilip, yapılamayacağını sınırlayabilirsiniz. [Authorize(Roles = “user”)] gibi. İyi günler dilerim.
Çok güzel bir makale teşekkürler. Veri alışverişinde Bearer kullanıp encrypt yapabilir miyiz? Yaparsak doğru bir yöntem sayılır mı? Amacım verilerin gizliliği.
Merhaba teşekkürler. Evet yapabilirsiniz zaten OAuth 2.0 Authorization Framework’ü ile beraberinde gelen Bearer token bir standardizasyon haline gelmiştir. Makale içeriğimiz de buna dayanmaktadır. HTTP protokolü söz konusu olduğu için verilerin gizliliği ne kadar sağlanılabilir bu tartışılır ve sizin architectural tasarımınızada bağlı bir etmen bu. Buna ek olarak da SSL kullanımını önerebilirim.
Merhaba,
Gayet anlaşılır ve faydalı bir paylaşım olmuş, teşekkürler. Bir sorum olacak; Owin de token tam olarak nasıl bir yapıda tutuluyor?
Store yapısı tamamen size kalmış. Token’lar machine key’lere göre serialize ve deserialize ediliyor. Oluşan token’ı siz store etmelisiniz.
Teşekkür ederim, peki web api dokümantasyonu için ne tavsiye edersiniz? Swagger denedim fakat swagger’da token based authentication’ı ekleyemedim.
Merhaba Swagger tarzı Apiary’a da bakabilirsiniz. Swagger’da authorization işlemleri mümkündür. https://github.com/domaindrivendev/Swashbuckle sayfasında “Describing Security/Authorization Schemes” başlığını inceler, biraz google’larsanız örnekleri bulabilirsiniz.
Merhabalar,
Swagger’ı Windows Service üzerinde self-host koşturduğum web-api ile kullanabiliyormuyuz. Swashbuckle.Core üzerinden yapılıyor görünüyor ama standart win service app yada console app üzerinde yapan birilerini bulamadım
Tekrar merhabalar,
Swagger’ı Swashbuckle.Core ile win service üzerinde çalıştırdım. Şimdi biraz custom rooter üzerinde çalışmam gerekiyor.
Teşekkürler.
Merhaba, çalıştırabilmenize sevindim.
Merhaba,
Bu tür Authentication ile ilgili anlamadığım konu, kullanıcı adı ve şifrenin client tarafında oluyor olmasının güvenlik riski oluşturup oluşturmadığıdır. Yani Web uygulamasında AJAX ile Web Api’ye sorgu gönderirken kullanıcı adı ve şifreyi yazıyoruz.
url: ‘/Token’,
dataType: ‘json’,
data: { “grant_type”: “password”, “username”: “Gokhan”, “password”: “123456” },
Bu güvenlik bilgilerin bilen biri postman, fiddler gibi bir tool ile çok rahat POST veya GET yapabilecek. Benim derdim Web API’min sadece benim sitemden çağrılıyor olmasıdır. Bunu nasıl yapabilirim. Yani http://www.deneme.com/GetUrun/Kategori/7 şeklindeki bir sorgunun sadece deneme.com çatısı altında yapılmasıdır. Başka bir siteden veya tool aracılığıyla kesinlikle çağrılamamasıdır. Çünkü buradaki “7” değerine rastgele değer gönderilerek sunucudaki tüm data çekilebilir.
Örneğin bir EXE yazarak aşağıdaki URI’daki adana ifadesi yerine kelimeler yazarak birçok kez call edebiliyorum. Bunu engellemek mümkün mü. HTTP üzerinde özel header mi yazmak gerekiyor Veya Session nesnesi falan mı kullanmak gerekiyor. Server tarafında aynı süre içerisinde çok sayıda post gelirse engelleme yapabilirim belki.
https://www.sahibinden.com/ajax/search/phrase?q=adana&categoryId=0&_=461305609903
Merhaba, ilk olarak kullanıcı adı ve şifre yolluyoruz kısmındaki düşüncenize gelecek olursak; kişi access token alabilmek için ilk adımda bu authentication api’a bu sorguyu göndermek zorunda ve genelde bu api SSL ile korunmaktadır ve SSL ile korunmasıda önerilmektedir. İkinci olarak da AJAX ile göndermek zorunda da değilsiniz, backend de yapabilirsiniz bu işlemi. Asıl sorunuza gelecek olursak da, aynı domain çatısı altında sorgularınızın sadece çağrılmasını istiyorsanız buda CORS (Cross-Origin) olarak adlandırılıyor ve sadece aynı sizin belirlediğiniz URI çatısında istekler cevaplanabiliyor. Burayı inceleyebilirsiniz.
SSL ile korunması dış uygulamaların bunu okumasını, HTTP paketlerinin okunmasını engelleyecek ama AJAX içerisinde bana bir fayda sağlayacak mı. Yani kullanıcı adı ve şifreyi POSTMAN’a yazdığım zaman yine çalışacak.
İkinci konu AJAX ile göndermek zorunda değilsiniz kısmını biraz daha açabilir miyiz. Bunu nasıl engelleyebiliriz. Mobil uygulama tarafında değil de Web uygulaması tarafında örneğin bir buttona tıklandığı zaman AJAX ile Web API çağırdığımızı düşünelim bu durumda backend’e authentication işlemi nasıl olacak.
CORS olayı için teşekkür ederim, benim için yönlendirici oldu.
Önemli olan zaten dış uygulamaların bunu sniffleyememesi. CORS’u yaparsanız zaten Postman veya Fiddler ile bir istekde bulunamayacaksınız. İkinci olarak da REST API entegrasyonunu bu kadar simple düşünmeyin. Herşeyiniz fontend üzerinden AJAX request’leri ile gelsin, gitsin olamaz ki bu kadar güvenliğe takmış ve önem vermiş durumdaysanız. UI tarafındaki Controller’ınızı bir Gateway olarak düşünün. Artık oradaki business’ınız her neyse, asıl REST API’ınızı consume edecek olan request’ler controller tarafında oluşturabilirsiniz. Bu kısımlar artık sizin yoğurt yiyişiniz ve projenizin mimarı dizaynları ile alakalı bir durum.
Kitabınız çıktı mı acaba
ASP.NET WEB APİ KİTABINIZ NE ZAMAN ÇIKIYOR
Merhaba bazı problemlerden dolayı biraz geçikti bu yaza çıkartma planımız. Proje video’su çekme aşamasındayız. Saygılar.
Kardeşim eline sağlik cok guzel bir makele olmus.web api ile calismaya basladigimdan beri nasil güvenlik önlemi alacagimi düşünüyordum.kendi sistemime uyguladim sorunsuz bir sekilde calisiyor tsk ederim.küçük bir sorum olacak facebok twitter foursquere gibi sitelerin apileride ayni mantiktami calismaktadir yanitlarsan sevinirim kolay gelsin.
Tam olarak arka plandaki logic’lerini bilemem fakat evet, OAuth 2.0 ile çalışmaktadır.
Merhaba Gökhan Bey,
Sorum direk yazı içeriğiyle ilgili değil ama , günümüzde asp.net mvc kullanılan ticari girişimlerde asp.net mvc’nin hazır sunduğu authentication mekanizması mı kullanılıyor?
Merhaba, bu çok genel bir soru olmuş. 🙂 Ooradaki developer’in ekmek yiyişi ile alakalı bir durumdur diyeyim. İster .Net içerisinde gelen authentication mekanizmalarını kullanır, ister kendisi custom authentication yapısını geliştirir. Bunu bilemem. 🙂
merhaba anlatımınız için teşekkür ederim ben servislerimi android client tarafında kullanıyorum bu şekilde nasıl güvenli hale getirebilirim android tarafınndan yani java tarafundanmı sabit kullanıcı adı şifre verip tokeni alıp sunucuya tekrar gönderecegim
Merhaba, evet app’inizin ilk login ekranında mecburen authentication sunucunuza token key alabilmek için kullanıcı adı ve şifreyi göndermeniz gerekmektedir. Onun dışındaki işlemlerde elde etmiş olduğunuz token ile ilerleyebilirsiniz.
Merhaba Gökhan bey. Ufak bir sorum olacak.
1. Büyük çaplı bir Web Projesinde Token güvenliğe ihtiyaç olur mu? Bu güvenlik seviyesi sizce hangi aşamadan sonra gerekli olacaktır? İleride bu projeyi kısmi yada tamamını mobile taşımak gerekirse diye soruyorum…
2. Tokenları api tarafında nasıl tutmak gerekir sizce? Sonuçta bir ikili yapımız var. Token alan kişi ve Token Key. Bunu Sesion da tutabiliriz yada db ye yazabiliriz.. Sizce hangisi?
3. Böyle bir Token sistemi ne kadar yorar sistemi? Sürekli her servis çağırımında gidip gidip bakmak gerek kullanıcının Tokenı varmı yok mu? diye..
Merhabalar, 1. sorunuz için eğer api based bir sistemle çalışıyorsanız ve internal olan resource’larınızı daha sonra dışarıya extend edecekseniz eğer token based bir güvenliğe ihtiyaç duyabilirsiniz. 2. sorunuz için token’ları api tarafında tutmayacaksınız, token yapisi sizin göndermiş olduğunuz kullanıcı adı ve şifreye ve içerisine extra olarak tanımlamış olduğunuz claims bilgilerine göre machine key’lere bakılarak hash’lenir. Token’ı resource’larınızı kullanacak olan client tarafında tutmalısınız. Token tarzı işlemler için db bazlı bir yerde tutmanızı önermem çünkü çok fazla ihtiyacınız olacak ve her seferinde db’ye erişmek size ek bir maliyet getirecektir. 3. sorunuza gelecek olursak, her servis çağrınızda token apinize gitmeyeceksiniz. Normal resource’larınızın bulunduğu api’de owin’i implemente ettiğinizde token expire süresine veya token key’in olup olmadığına göre orada da kontrol edilmektedir zaten.
Gökhan bey merhabalar. Öncelikle cevabınız için teşekkür ederim. Beki daha önce soruldu belki sorulmadı bilmiyorum. Bir sistem tasarlıyorum. Bir binaya girişte kimlik sorulacak. Ok. Token ile bu işi yaptık. binaya giren herkesten kimlik bilgisini aldık.
2. olarak bina içindeki her odaya girişte bir kimlik kontrolü daha yapmam lazım. Kapıdan her giren o odaya girmeye yetkili olmayabilir. Yetkisi olsa yada olmasa bile benim x kişisi y odasına girdi bilgisini loglamam gerekli. Bu durumda Token üstünde geçerli kişiyi bulursam işimi görür diye düşünüyorum.
Sorum
1. Bu bilgiye nasıl erişirim?
2. sizin önerebileceğiniz daha farklı bir yapı olur mu? Odaların dinamik olarak sayı ve yetkisinin değişmesi unsurunu göz önünde bulundurursak…
Merhaba kullanıcı bilgilerine daha önceki yorumlarda da cevapladığım gibi “System.Web.Http namespace’i altında bulunan User context’i üzerinden ulaşabilirsiniz”
Öncelikle örnek için teşekkür ederim ancak uygularken bir hata ile karşılaştım.
using AspNetWebAPIOAuth.OAuth.Providers;
satırında Provider assembly’sini kabul etmiyor, bahsettiğiniz paketler yüklü ancak build hatası alıyorum.
OAuth klasörü ve onun içinde de Providers klasörü olmalı sanırım
Merhaba,
Hocam, birkaç sorum var. Beni bilgilendirebilirseniz sevinirim.
1 – Dikkatimi çekti. identity.AddClaim(new Claim(“sub”, context.UserName)); ifadesinde “sub” ne anlama geliyor. Birşeyin kısaltılması mı.
2- Asıl sorum şu; giriş yapılırken oluşturduğumuz bilgilere diğer metodlardan nasıl erişeceğiz. Örneğin kullanıcı giriş yaptıktan sonra kullanıcının mail adresini, adını soyadını da yükleyip sonraki fonksiyonlardan erişmek istiyorum. ,Aşağıdaki sayfada claim okuması gösterilmiş ancak Foreach ile tüm claim’leri listeleyince claimtype alanı hepsi için http://www.w3.org/2001/XMLSchema#string görünüyor.
https://msdn.microsoft.com/en-us/library/ee517271.aspx
public override Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
bool kullaniciKontrol = KullaniciKontrol(context.UserName, context.Password);
if (!kullaniciKontrol)
{
context.SetError(“invalid_grant”, “Kullanıcı adı veya şifre yanlış.”);
return Task.FromResult(null);
}
var identity = new ClaimsIdentity(context.Options.AuthenticationType);
identity.AddClaim(new Claim(ClaimTypes.Name, context.UserName));
identity.AddClaim(new Claim(ClaimTypes.Gender, “Erkek”));
identity.AddClaim(new Claim(“Sirket”, “Deneme Şirketi”));
identity.AddClaim(new Claim(“sub”, context.UserName));
context.Validated(identity);
return Task.FromResult(null);
}
Okuma işlemini de şu şekilde yapıyorum.
[HttpGet]
[Authorize]
public List Liste()
{
var identity = (ClaimsIdentity)User.Identity;
IEnumerable claims = identity.Claims;
foreach (Claim claim in claims)
{
sonuc.Add(“claim.Value: ” + claim.Value);
sonuc.Add(“claim.ValueType: ” + claim.ValueType);
}
return sonuc;
}
3 – Son sorum da LOGOUT / SIGNOUT işlemini nasıl yapabiliriz veya belli bir ticket i nasıl sistemden remove edebiliriz.
–DÜZELTME–
Hocam,
önceki mesajımdaki 2.soruyu görmezden gelin.
sonuc.Add(“claim.ValueType: ” + claim.ValueType); ifadesinde ValueType yazmışım oysa sadece Type yazılmalıydı. Gözden kaçmış.
Şimdi sadece 3 solu sorum için desteğinize ihtiyacım var. LOGOUT işlemini nasıl yapabiliriz veya önceden oluşturulmuş bir token i nasıl geçersiz yapabiliriz.
Merhaba, daha öncede cevapladığım gibi: “bu tarz session’ları sizin tracklemeniz gerekmektedir. API stateless olduğu için görevi sadece geçerli bir süreye sahip token üretmektir. Handle işlemini unique bir id kaydedip o id üzerinden siz takip edebilirsiniz, logout olduğunda farklı unique bir değer atamak gibi vb. çözümler düşünebilirsiniz. Aktif olmadığı durumlarda ise zaten token expiry olacaktır.”
Merhabalar benim size bir sorum olacak isin icinden cikamaz haldeyim:)
Requesti atip tokenimizi aldik burada sorun yok. Fakat kullanici sifresi degistiginde veya rol degistiginde degismeden once aldigi token yine aktif oluyor.bunun onune nasil gecebiliriz?
Merhaba, bu tarz session’ları sizin tracklemeniz gerekmektedir. API stateless olduğu için görevi sadece geçerli bir süreye sahip token üretmektir. Handle işlemini unique bir id kaydedip o id üzerinden siz takip edebilirsiniz, logout olduğunda farklı unique bir değer atamak gibi vb. çözümler düşünebilirsiniz. Aktif olmadığı durumlarda ise zaten token expiry olacaktır.
Eline sağlık panpa sayende owin i kullandım
Kardeşim çok teşekkürler paylaşım için bir şey soracağım ben bu işlemi postman da gerçekleştirdim fakat browser da apinin get metodunu çağırdığımda {“Message”:”Authorization has been denied for this request.”} mesajını alıyorum.Bunu webde de getirebilmem için ne yapmam gerekir bir açıklarmısın? Teşekkürler.
Merhaba problem hala devam ediyor mu?
[…] Kaynak: https://gokhan-gokalp.azurewebsites.net/asp-net-web-api-token-based-authentication/ […]
[…] Gökalp Eylül 16, 2016 No […]
Merhaba Gokhan Bey,
Hem bu yaziniz hem de refresh token kullanimi yaziniz icin cok tesekkurler. Adeta hayat kurtardiniz
Iyi Calismalar
Ben teşekkür ederim, kolay gelsin.
Merhaba
public override async Task GrantResourceOwnerCredentials
ve
public override async System.Threading.Tasks.Task ValidateClientAuthentication
Kısımlarında await kullanılmadığı için altını yeşil olarak çiziyor.
yoğun kullanıcı kitlesine sahip uygulamalarda sorun yaratırmı?
Merhaba Gökhan,
Bu değerli yazın için çok teşekkürler.
Android uygulamam için Web API geliştirdim ve Auth sistemini senin bahsettiğin şekilde yaptım.
Sorun şu ki , Web API’mdeki her metod Auth gerektiriyor ve kullanıcılarım uygulamamı kullanınca bazen Web API çalışmaz hale geliyor…
Böyle olunca sunucudan IIS ‘ e girip siteyi yeniden başlatıyorum ve sorun düzeliyor…
Sence bunun çözümü nedir ? Token sistemi IIS ‘ i yoruyor olabilir mi ?
Uygulamam çalışırken metodlarımda genelde veri tabanımdan 30-50 satırlık veri çekiyor (Uygulama başladığında bunun gibi 3,4 istek yapıyor… , bu isteklerle de alakalı olabilir mi ?)
İyi çalışmalar…
Merhabalar, öncelikle ben teşekkür ederim.
Sorunuza gelecek olursak eğer API method’larınızın authentication gerektiriyor olmasının ve yük altında “çalışmaz bir hale gelmesi” konusu, ne API ile nede auth işlemleri ile alakalı olduğunu düşünmüyorum. Burada kodlamanızdan kaynaklı bottleneck’leri herhangi bir APM tool’u ile adresleyebilirsiniz. Tahminimce memory leak yaratan bir kod bulunmakta. Ezbere konuşmak zor bu tarz işlemler için.Eğer prod ortamlarınızda newrelic gibi apm tool’ları var ise, bir performans raporu almanızı önerebilirim.
Tekrardan merhaba Gökhan,
İlgin için çok teşekkürler.
Kodlarımın tamamını inceledim ve her bir API çağrımda MySql bağlantısı oluşturduğumu ve sonradan birçoğunun MySql bağlantılarını kapatmadığımı farkettim , tamamen kodları yeniden düzenleyince bi sorun olmadı.
Dediğin araçları kullanıp temiz bir analiz yapamadım ama çalışıyor şuanlık 😀
İyi çalışmalar…
Merhaba,
Aşağıdaki kodları tam olarak anlayamadım UserName ve Password ne amaçla kullanılıyor Sqlconnection satırında mssql servera bağlanırken ki gibi tek seferlik bir username ve password mu yoksa benim database serverıma bağlanıp User tablomda ki kullanıcılar mı ?
if (context.UserName == “Gokhan” && context.Password == “123456”)
{
var identity = new ClaimsIdentity(context.Options.AuthenticationType);
identity.AddClaim(new Claim(“sub”, context.UserName));
identity.AddClaim(new Claim(“role”, “user”));
context.Validated(identity);
}
Şimdiden Teşekkürler,
Merhaba o kısım kullanıcılarınızın login sırasında token alabilmeleri için gerekli olan standart username, password bilgileridir. Tabi bu kısmı kendinize göre tailor bir business yapabilirsiniz.
Güzel uygulama olmuş teşekkürler. Şöyle bir problemim var. Benim uygulamamda login olurken 3 ayrı parametre alıyorum. Burada sadece kullanıcı adı ve şifreye göre yapılmış.
Kullanıcı Adı, Şifre, TC
Ne yapmam lazım ?
Merhaba, additional parametreleri “OAuthGrantResourceOwnerCredentialsContext” üzerindeki Request property’sinden erişebilirsiniz. Örneğin:
var requestForm = await context.Request.ReadFormAsync();
requestForm[“additionalParameter”] gibi.
Saygılar.
Merhaba,
Öncelikle faydalı yazınız için çok teşekkür ederim.
Sistemimde user authentication’a ek olarak, application authentication da olacak. Dolayısı ile username – password ikilisinin yanında clientId (bu zaten context’te mevcut) ve client password’e ihtiyacım olacak.
Client Password bilgisini yukarıda bahsettiğiniz Additional Parameters’da mı almam mantıklı yoksa başka bir yol mu önerirsiniz application authentication için ?
Merhaba,
Client doğrulaması için client id ve client secret gibi bilgiler kullanılmakta standart olarak. Validation işlemini ise “ValidateClientAuthentication” method’unda gerçekleştirebilirsiniz.
ClientId’yi OAuthGrantResourceOwnerCredentialsContext ve OAuthValidateClientAuthenticationContext nesnelerinin altında görebiliyorum ama Client Secret property’sini göremedim. Onu nereden almak gerekiyor ?
Client secret’a neden ihtiyacınız var?
Spesifik olarak Client secret’a ihtiyacım yok aslında. Benim client id ve clientpassword ikilisine ihtiyacım vardı. Client Id zaten context’te mevcut, Header’a da clientpassword’u ben ekleyerek çözmüştüm ama siz client secret yazınca header’a eklediğim clientpassword alanının yerini tutuyor sanıp o yüzden sormuştum. Sanırım yanlış anlamışım kusura bakmayın 🙂
Hocam tekrar merhabalar, basic Asp Net Web Api 2 projesi ile bir proje tamamladım ancak bilemediğim bir nedenden dolayı access_token belli kullanıcılarda çok uzun bir string oluyor. Daha sonra token’i header’a ekleyip post ettiğimde ise ;
HTTP Error 400. The size of the request headers is too long.
Hatasını alıyorum. Sunucu tarafında bunu çözemedim IIS’de internette geçen tüm ayarları denememe rağmen bu hatayı vermeye devam ediyor. Token uzunluğunu optimize edebilir miyim?
Selam, problem hala devam ediyor mu?
Evet devam ediyor, Jwt token’a geçemyi düşünüyorum ne dersiniz?
Merhaba, JWT’nin çözüm olacağını düşünmüyorum. Token string’inin çok uzun olmasının sebebi token içerisine neler ekliyorsunuz? Claim’ler vb? Nasıl bir data koyduğunuz ile alakalı bir durum bu.
Merhaba. Öncelikle kitabınızı okumaya yeni başladım, gerçekten çok güzel bir kaynak. Ben aşağıdaki gibi web servis fonksiyonuna rol tabanlı erişim izni vermek istiyorum. Bunu nasıl yapabilirim?
[Authorize(Roles = “Admin”)]
public List List()
{ /*Komutlar*/ }
Şimdiden teşekkürler.
Selamlar, bu işlemleri claim’ler ile yönetebilirsiniz. Token’ı ürettiğiniz yerde kullanıcının claim’ine rolleri set edebilirsiniz. Kolay gelsin.
İlginiz için teşekkür ederim. Peki oluşturulan token bilgileri nerede saklanıyor? LoadBalancer’lı bir mimariyi düşündüğümüzde farklı makinalarda oluşturulan tokenları diğer makinalar üzerinde oturum açılmaya çalışıldığında oturum açılır mı? Eğer oturum açılmazsa böyle bir senaryoya nasıl bir çözüm bulunabilir?
Token bilgileri herhangi bir yerde persist edilmiyor. MachineKey bilgileri ile encrypt ediliyor. Load-balancer kısmında bir karışıklık var sanırım. Identity server’ınız lb arkasında ise ve farklı makineler da ise, aynı farmda olabilmeleri ve aynı key’leri üretebilmeleri için machinekey bilgilerinin de aynı olması gerekmektedir. Identity server’ı cluster olarak kurduğunuzda da böyle bir şeye gerekte kalmayacaktır. Eğer identity server yerine custom bir api üzerinden owin context’i ile key’leri siz üretiyorsanız, ozaman ihtiyaç duyacaksınız. Kolay gelsin.
Merhaba, adımları uyguladığımda hatta sizin paylaştığınız uygulamayı indirip onda test ettiğimde
The requested resource does not support http method ‘POST’. hatası alıyorum
Çözüldü teşekkür ederim. Get işlemini /token yerine yine apinin adresinde denemişim
Merhaba,
Makalede bahsettiğiniz token alma ve veri çekme ile ilgili yapıları bir c# windows forms uygulamasında kullanılacak şekilde örneklendirebilir misiniz? Yani orderscontroller tarafından sağlanan verilere windows forms ile ulaşmak istiyorum ve aynı zamanda oAuth kullanmak istiyorum.
Merhaba, istediğiniz platform’da kullanabilirsiniz. Tek yapmanız gereken REST request’lerini nasıl gerçekleştirebileceğinize bakmanızdır. RestSharp kütüphanesi bu konuda size yardımcı olabilir. İyi günler.
Çok teşekkür ederim. RestSharp ve Postman’deki Generate Code Snippets işimi gördü.
Sevindim. 😉
Gökhan Hocam saygılar,
tek kelime ile excellent 🙂
Merhabalar,
Çok güzel bir örnek olmuş. Token pat ile ilgili bir sorum olacaktı.
TokenEndpointPath = new Microsoft.Owin.PathString(“/token”)
tokenendpoint pathi “/wp/token” şeklinde nasıl tanımlayabiliriz. Yada böyle bir tanımlama yapabilir miyiz.
Teşekkürler.
Merhaba sizin tanımladığınız gibi. PathString(“/wp/token”)
Merhaba makeleniz için teşekkürler. Anlayamadığım bir nokta var. Makelenizde;
“Authorization Server bu bilgileri doğrulursa, client’a bir Access Token Http Response’u döner.” ve
“Client artık erişmek istediği servislere, elde etmiş olduğu Access Token’ı Http Request’in Authorization Header‘ına ekleyerek erişim sağlar.” diye yazmışsınız.
Toke’nin Headera eklenmesiyle yapılan isteklerde, sistem temel olarak token doğrulamasını nasıl yapıyor? Yani, oluşturularak Clienta göndereilen Token aynı zamanda server tarafında tutuluyor mu? Tutuluyorsa hangi logic ile? Cache mi database mi?
Merhaba tutulma işlemi bulunmamakta. Her şey on the fly olarak gerçekleşiyor. Token alınırken veriler encrypt ediliyor, daha sonrasında ise decrypt işlemi gerçekleşiyor ve bu işlem sırasında da expire time’ları da göz önünde bulunduruluyor. Token ile gelinen endpoint üzerinde owin kurulu ise kendisi bu pipeline’ı otomatik olarak işletiyor.
Saygılarımla.
Merhaba,
Çok bilgilendirici bir yazı olmuş teşekkür ederim.
Biraz temel kısımda takılmış olabilirim ama şu kavramlarda sanırım bir sıkıntım var. Bildiğim kadarıyla;
Authentication : Kullanıcının siteme giriş yapmasını kontrol eden sistem
Authorization : Giriş yapmış kullanıcının ilgili işleme erişimini kontrol eden sistem
Yazı başlığında ve konusunda authentication işlenmesine rağmen neden Authorize attribute’ü kullandık ?
Aşağıdaki makalede Authorize attribute’ünü Authorization kısmında kullanmışlar bu yüzden biraz karıştırdım sanırım
https://docs.microsoft.com/en-us/aspnet/web-api/overview/security/authentication-and-authorization-in-aspnet-web-api
Merhaba evet kavramlar doğru. Attribute konusuna gelirsek, authentication client’ın makinaya erişmesine bakarken, authorization ise ilgili kullanıcının gerçekleştirmek istediği request’e izni var mı yok mu gibi konulara bakmaktadır. Pipeline’a baktığınızda ise, en son AuthorizationFilter’lar gelmektedir. Burada ise ilgili scope ve claim’ler doğrultusunda kullanıcılara işlem yaptırılabilmektedir. Bu sebeple en authorize attribute’ü kullanılmaktadır.
merhaba,
token üretirken grant_type = password yerine grant_type = client_credentials olarak token üretmek istersem ne yapmam gerekiyor ?
Merhaba, herhangi bir şey yapmanıza gerek yoktur. Client credentials flow’u ile ilerlemek istiyorsanız grant_type’ı set edip, client id ve client secret ile devam etmelisiniz.
hocam kolay gelsin, kafama şey takıldı, şimdi sunucu tarafında üretilen token keyleri, acaba sunucuda bir yerde depolanıyor mu, zira token kullanarak istek geldiğinde karşılaştırmayı nasıl yapacak?
Merhaba, depolanmamaktadır tüm işlemler on the fly olarak hesaplanmaktadır. Bunu daha önceki yorumlarda cevaplamıştım. Token’lar machineKey’e göre encrypt ve decrypt edilmektedir.
Merhaba,
Token’ı tek kullanlık nasıl yapabiliriz ? Yani oluşturulan her token yalnızca 1 kere kullanılabilsin. Her method çağrıldığında farklı token istesin
Merhaba neden böyle bir şeye ihtiyacınız var? Token’ın kullanım amacı bu şekilde olmamalı OAuth çatısı altında. Eğer method based credentials’a ihtiyacınız varsa da, bunları scope’lar ve claim’ler ile yönetebiliyor olmalısınız. Saygılar.
Hocam saygılar. Bir mobil projem var, verileri servisten çekiyorum. Ben token olayını şu şekilde yaptım. Client servise kullanıcı adı parola ile geliyor, bilgiler doğruysa o kulanıcıya token olarak guid atıyorum ve sqlservere kaydediyorum(atadığım bu tokeni cliente result ediyorum oda kendi hafızasına alıyor.). Daha sonra client sorgulama ekranına gelip sorgulama parametrelerinin yanında birde tokeni yolluyor. servis bu tokene sqlserverdan bakıp geçerli oturum olup olmadığına bakıyor oturum geçerliyse sorgulama sonucunu döndürüyor. doğru değil veya süresi dolmuşsa hata dönderiyirum. ben sistemimi bu şekilde kurdum. Sizin bu anlattığınız sisteme geçsem mi diye düşünüyorum. Sizce geçmelimiyim. Benim sistemimden farkı daha güvenlikli olmasımı yoksa benim sistemimde aynı işi yapıyor mu?
Birde ben kendi sistemimde: kullanıcı bir kere girip token aldıktan sonra sistemden çıkıp tekrar girerse veya başka bir cihazdan oturum açarsa eski oturumu iptal ediyorum. bunu bu sistemde şöyle yapmayı düşündüm:
/token den kullanıcıya tokeni return ettim aynı zamandada sqlserverde log tabloma bu tokeni kaydettim. daha sonraki girişlerde aynı kullanıcı tekrar girerse eski oturmu iptal edeceğim.
sizce mantıklımı?
OAuth standartlarında bu tarz bir işlem yapabilmek standart dışı olarak ancak, custom bir şekilde gerçekleştirebilirsiniz. OAuth için token’ın bir expire date’i vardır ve expire date’i geldiğinde sona erer. Eğer business’ınız bunu gerektiriyorsa tek bir oturumu, custom olarak gerçekleştirmelisiniz.
Merhaba, token’ları persist etmeniz çok efektif olmayacaktır. OAuth 2.0 standartlarında token’ları bearer olarak on the fly yapmanız sizin yararınıza olacaktır. Saygılar
Merhaba, Token dönerken yanında farklı bir bilgi daha döndermek istiyorum(örn kullanıcıId) nasıl dönderebilirim.
Merhaba bu bilgileri zaten claim olarak set edebiliyorsunuz, makaledeki gibi “new Claim(“sub”, context.UserName)” gibi. Saygılar
identity.AddClaim(new Claim(“UserId”, “12345”));
olarak eklesem bile Json dönüşünde sadece access_token,expires_in ve “bearer” bilgileri görüüyorum. Burada UserId ninde dönmesini istiyorum. Nasıl yapabilirim?
Merhaba, claim üzerine set ettiğiniz bilgileri ilgili client üzerinden kullanıcı validate olduktan sonra, System.Web.Http namespace’i altında bulunan User context’i üzerinden ulaşabilirsin. Saygılar.
Gökhan merhaba, Yazdığım bir api servisine hangi domainlerden istek geldiğini nasıl görebilirim.
Amacım api’i kullanan siteleri tespit etmek. ajax ile gelen isteklerde Request.UrlReferrer den görebiliyorum ama mesela Asp.Net Mvc de backend den httpclient ile yaptığım bir istekte UrlReferrer değeri boş geliyor.
Merhaba, eğer null’sa yapılabilecek bir şey var mı bilemiyorum. Eğer probleminiz farklı domain’lerden api’ınızın call edilmesi ise, cors ayarlarını yapmanızı tavsiye ederim. Bir diğer çözüm ise urlreferrer kontrolü yapmanız olacaktır null mı değil mi gibi. Kolay gelsin.
Merhaba, öncelikle authentication konusundaki aydınlatıcı fikirleriniz için teşekürler.
Ben örnek projenizi indirip postman tool ile sıkıntısız işlemler yaptım.
Yardım istediğim konu postman(bir metoda authenticate olup ticket alma sonra bu token ile başka metod çağırma) ile yaptığımız işlemleri asmx web serviste backened olarak nasıl yapabilirim. Biraz denedim ama işin içinde çıkamadım.
token ile asmx web servisi authentication örnek bir kod gösterebilir misiniz
Teşekürler..
Saygılarımla
Merhaba, teşekkür ederim öncelikle. Nacizane tavsiyem, eğer mümkünatı varsa ilgili servisinizi Web API ile değiştirmek olacaktır. Çünkü bir çok işlem, Owin middleware’i ile Web API’ın pipeline’ında handle edilmektedir. Asmx üzerinde daha önce hiç bu tarz bir OAuth implementasyonu denemedim açıkcası. 🙂 Fikir vermesi açısından, en azından nasıl consume edilir konusuna örnek bir kaç link var gibi. http://stackoverflow.com/questions/4734397/using-an-oauth-access-token-to-access-soap-service birde https://www.avisi.nl/blog/2012/11/22/consuming-oauth-secured-soap-webservices-using-spring-ws-axiom-signpost/
Her şeyi teker teker ve sade bir dille açıklamışsınız, teşekkürler.
Yardımcı olabildiyse, ne mutlu bana. 🙂
[…] Kaynak: Asp.Net Web API – Token Based Authentication […]
Merhaba, öncelikle makale için teşekkür ederim. Güzel olmuş. Ajax post ile token alma konusunda sıkıntı yaşamıyorum fakat ajax post güvenli gelmediği için post işlemini controller içerisinden yapmaya çalıştığımda bir türlü context parametrelerini geçemedim.
https://i.hizliresim.com/ZZ8YX0.jpg
Merhaba, size tavsiyem restsharp gibi rest call wrapper library’lerini kullanmanız olur. 🙂
Anlatım gayet güzel olmuş eline sağlık. Kurulumu yaptım web api uygulamam için postman üzerinden testini gerçekleştirdiğimde token alma ve bu token ile request gönderme işlemleri başarıyla çalıştı. Ancak tek bir problemim var jquery ajax ile token almak için post işlemi gerçekleştirdiğimde 404 (Not Found) ve No ‘Access-Control-Allow-Origin’ header is present on the requested resource. hataları alıyorum. Web api çağırılarımda da aynı hatayı alıyordum httpResponseMessage.Headers.Add(“Access-Control-Allow-Origin”, “*”); ekleyerek çözmüştüm. Ancak oauth ‘da bu yeterli olmadı. Çözüm için öneriniz var mı.
Merhaba öncelikle “GrantResourceOwnerCredentials” implemente ederken oradaki CORS ayarlarını set ettiniz mi?
Merhabalar, örneklendirmeleriniz ve makaleniz için çok teşekkür ederiz. Gerçekten çok makbule geçti ve fayda gördüm. Yalnız bir konuda size danışmam gerekti. Örneğinizde bahsettiğiniz yetkilendirmeleri yaparken metod başına [Autorize] özniteliğini yerleştiriyorsunuz.
Ben simple membership kullanmıyorum ve kendi üyelik sistemim var. Metodun başına koyduğunuz [Authorize] özniteliği membership için mi yoksa OAuth 2.0 nin bir parçası mı, açıkçası tereddütte kaldım.
Bu konuda bir fikriniz var mıdır ? Hazır membership kullanmıyorsak, OAuth 2.0 yi implement edebiliyor muyuz projemize ?
Teşekkürlerimi sunarım.
Ayşe
Merhaba, Authorize attribute’ü “System.Web.Http” içerisinden gelmektedir. Ister OWIN ile OAuth imp. kullanabilirsiniz, isterseniz de eğer simple membership provider kullanıyorsanız onunlada kullanabilirsiniz. Teşekkür ederim.
Merhaba , username password e ek olarak bir parametre daha göndermek istiyorum acaba ne yapmam gerekli anlatım için teşekkürler
Merhaba, additional parametreleri “OAuthGrantResourceOwnerCredentialsContext” üzerindeki Request property’sinden erişebilirsiniz. Örneğin:
var requestForm = await context.Request.ReadFormAsync();
requestForm[“additionalParameter”] gibi.
Saygılar.
Merhaba,
Token oluşturulduktan sonra kullanıcı şifre değişikliği yada kullanıcı yetkilerindeki değişikliklerde daha önce alınan token ı nasıl iptal edebiliriz?
Merhaba, bu konuda en çok sıkıntı çekilen nokta burası açıkcası. Çünkü token’ları store etmediğimiz için on the fly hesaplandığı için bu tarz işlemler malesef ki mümkün değildir. Bu işlemin best practice’i şudur diyemiyeceğim. Manuel işlemler yapıp, token’ı kontrol etmemiz veya expire sürelerini optimum süreler vererek, tekrardan yeniletmeye zorlatmalıyız.
merhaba. sadece access_token değerini döndürmenin bir yolu var mı? sadece verilen token değerini döndürmek istediğimde ne yapmalıyım?
Merhaba bu konudaki tam isteğiniz nedir acaba? refresh token olmadan mı?
Hocam makaleyi güncelleseniz ne güzel olur. Mesela bu oluşturduğumuz tokenler nerede tutuluyor?
Rolleme nasıl yapılır? İyi çalışmalar
Merhaba, evet vakit bulduğumda güncellemeyi planlıyorum biraz daha detaylı, OAuth2 standartlarına uygun vb. bir şekilde.
Not: Tokenlar on the fly üretilmektedir, bir yerde store edilmiyor.
Selamlar,
Hazirladigim sistemde 2 islem mevcut. Bir normal kullanicilarin kullandigi panel, digeri de entegre olup web api ile veri cekecek olan kullanicilar. Normal kullanicilar icin mvc5 icerisinde default gelen Owin Authentication kullaniyorum. Api icin de makalede anlattiginiz islemleri yaptim token degerimi aldim fakat token parametresi gelmemisse ya da username / password bilgisinden biri yanlissa Account/Login sayfasina yonlendirme islemi yapiyor.
Authentication islemlerinde normal kullanici ile api kullanicisini nasil ayirabilirim? Yani sormak istedigim normal kullaniciya View ile sonuc dondurmek isterken api erisimlerinde json veri basabilmek istiyorum bunu basaramadim. Konuyla ilgili fikir verebilirseniz sevinirim.
Merhaba, normal şartlarda ayırmamanız, yani ortak bir authentication işlemlerini yönettiğiniz bir API/IdentityServer olmalı ve her iki kullanıcı da login işlemleri için geçerli token’larını oradan almalılar. Yetkileri ise claim’ler le yönetmelisiniz. Sizin şuanki case’iniz de ise, User claim’i içerisine ayırt edebileceğiniz bir property set edebilirsiniz.
Merhaba,
grant_type=password ile deneme yaptığımda GrantResourceOwnerCredentials fonksiyonuna hiç girmiyor ve “error”: “unsupported_grant_type” hatası alıyorum. Hatayı nasıl giderebilirim?
İyi çalışmalar.
Merhaba, Json olarak data’yı gönderdiğinizden emin misiniz?
Controller içerisinde mevcut claim in rolünü değiştirmek veya yeni rol eklemek mümkün müdür ? bunu nasıl yapabiliriz yardımcı olabilir misiniz.
Teşekkürler.
Merhaba, malesef ve neden böyle bir şey yapmaya ihtiyaç duyuyorsunuz?
Hocam login işlevinde veritabanındaki bir değerin durumuna göre rol ekliyorum ve daha sonra bu rolü kullanıcı isterse değiştirebiliyor. Bu değişikliği api’de algılamam gerekiyor aksi halde rol kısıtlaması olan hiç bir istek cevap vermiyor.
Merhaba, kusura bakmayın geç cevap için, malum yoğunluklar. Öncelikle sormak istediğim şey: neden kullanıcı kendi rolünü değiştirebiliyor? Bu şekilde bir authorization nasıl olabilir ki? Sanki tasarımda bir hata var gibi geliyor bana.
Merhabalar.
Apiyi satın aldığım bir web hostinge upload edip deploy ettiğimde token alabiliyorum fakat.
api/Orders/List çağrısını ürettiğim tokenle sorguladığımda
Error – 404.0 – Not Found hatası alıyorum.
MapRequestHandler- Staticfile gibi bir hata alıyorum.
Sitede IIS 8.5 kurulu.
Acaba Api nin config ayarlarında bir şey mi değiştirmek gerekiyor bir fikriniz var mıdır ???
Application pool’da ASP.NET 4.0 seçili olduğundan emin misiniz? Eğer seçili ise, ISAPI filter’larına bir göz atınız.
Ellerine saglik guzel olmus
Teşekkür ederim.
Ben android uygulamam için bu şekilde bir webapi olulturdum ve çalıştırdım. Android uygulamamdan bu webapiyi nasıl çağıracağım ve işlemleri nasıl yapacağım? Android tarafı için bilginiz varmı yada yönlendirebileceğiniz bir kaynak ?
Bunun için çeşitli rest client’ları mevcut. Genelde en yaygını “OkHttp”, “Volley” var benim bildiklerim. Onun dışında çok bir bilgim yok malesef. 🙂
Merhabalar,
Yazı için çok teşekkürler detaylı bir anlatım olmuş. Apiyi test etmek için Fiddler,Postman kullanmadan bir asp projesi ile verileri çekebilirmiyiz?
Elimde örnek kod var ama bir türlü [Authorize] kullanarak çekemedim. Yol gösterirseniz sevinirim.Teşekkürler
Merhaba, beğenmenize sevindim. POSTMAN gibi bir tool kullanmadan herhangi bir REST client’ı ile de aynı işlemi gerçekleştirebilirsiniz. Örneğin Restsharp. [Authorize] attribute’ü ile çekme nedir acaba?
merhaba
AccessTokenExpireTimeSpan değerini bir gün gibi bir süre yaptığımda token geçerliliği bu süre olmuyor, bazen 20 bazen 40 bazen 200 dakikada token expire oluyor, bunun sebebi ne olabilir?
Merhaba, böyle bir problem ile karşılaşmadım hiç açıkcası. Deploy ettiğiniz (server) ve kullandığınız ortamlardaki “date” formatlarının doğruluğunu kontrol ettiniz mi?
Bu problemi bende yaşıyorum
iis üzerindeki machine keyi statik yapmak gerekiyormuş,
bir sorum daha var, metot bazlı exprire date belirtebiliyor muyuz?
Merhaba token’lar genel olarak bir expire date’e sahip. Method’lar üzerindeki işlem ve yetki kısıtlamalarını claim’ler ile yapabilirsiniz.
Aynı sorunu bende yaşadım. Çözümü static bir machine key belirleyiniz.
Uzak sunucudaki IIS restart olabilir. Özellikle hostinglerde.
Sorunu çözecektir.
Gökhan Bey Merhaba,
Makale için teşekkür ederim şimdiden. Emeğinize, bilginize sağlık.
Bir sorum var benim. Token oluşturduktan sonra expiration’ı 30 gün belirlememe rağmen uzak sunucuda ve local de ortalama 15-30 dk içinde expire oluyor ve token kullanılamıyor.
Sizce sebebi ne olabilir.
İyi günler dilerim.
Merhaba, bu konuda ezbere birşey diyemem fakat oluşan token’da “expires_in” alanındaki değerini kontrol ettiniz mi? Birde her token’ı valide etme işleminizde expire time’ı üzerinde herhangi bir değişiklik yapıyormusunuz?
Hocam çok başarılı makale olmuş. Ellerine sağlık. Teşekkür ederim
Ben teşekkür ederim. Yorumunuz için teşekkürler.
Merhaba,
Username ve password kısımlarını, asp.net Membership ile entegre edebilirmiyiz ?
Web Api’ye sisteme üye olanlar erişsin istiyorum, örneğin windows form application üzerinden login bilgilerini girdikten sonra web api’de doğruluğu kontrol edildiği taktirde diğer form ekranı açılsın veya mobil application tarafı içinde öyle.
Merhaba evet, kullanıcı doğrulama kısımları yani, username ve password alanlarını istediğiniz bir noktadan kontrol edebilirsiniz. Membership provider kullanıyorsanız ilgili servis’in kullanıcıdoğrulama method’u ile veya kendiniz custom bir provider yazarak da gerçekleştirebilirsiniz ilgili tablolar üzerinden.
Gökhan Bey merhaba,
Token alma işlemi IIS te ve ISSExpress te localde çalışıyor. Fakat restapi yi Reseller üzerinde hosta publish ettiğimde, Token almak isteğimde, “unsupported_grant_type” hatası alıyorum.
Diğer controllerlar ([Authorize] kaldırdığımda ) normal şekilde çalışıyor ama. Her şeyi denedim düzelmedi. Sebebi ne olabilir sizce ?
Teşekkür ederim.
Merhaba debug etmeden ne desem yalan olur 🙁 Hataya bakarsanız request üzerinde gönderdiğiniz “grant_type” parametresi yanlış gidiyor gibi gözüküyor…
Merhaba,
Cors ayarlarını set ederken username ve password verilerini programın içinde belirtiyoruz.
Bu verilerin veri tabanından gelmesi için ne yapmamız gerekiyor. Yani her kullanıcı kendi bilgilerini girerek token almasını nasıl sağlayabiliriz. Teşekkür ederim.
Merhaba, makale zaten bahsettiğiniz gibi. Sadece demo yapablmek için static kullanıcı bilgileri ile ilgili işlemi gerçekleştirdim. Sizin yapmanız gereken ise “SimpleAuthorizationServerProvider” class’ı içerisinde context üzerinden “UserName” ve “Password” bilgilerini static olarak değil, başka bir servis üzerinden gerçekleştirmek. Yani DB ile konuşacak bir user service’ini oraya implemente edebilirsiniz.
Merhaba,
SimpleAuthorizationServerProvider.cs sınıfında aşağıdaki satırda UserName ve Password tanımlamışsınız.Bende ise apikey ve secretkey mevcut bu iki kod birleştirip(https://www.base64encode.org sitesinde iki kod beraber girdiğimde elde ediyorum) bearer token oluşturuyorum. Username ve password yerine apikey ve secret key girdiğimde ise hata ile karşılaşıyorum.Konu ile ilgili yardımcı olabilir misiniz?
// CORS ayarlarını set ediyoruz.
context.OwinContext.Response.Headers.Add(“Access-Control-Allow-Origin”, new[] { “*” });
// Kullanıcının access_token alabilmesi için gerekli validation işlemlerini yapıyoruz.
if (context.UserName == “Gokhan” && context.Password == “123456”)
Merhaba, yapmak istediğiniz şeyi tam anlayamadım. Zaten bu API’ın amacı, bir bearer token generate etmek eğer kullanıcı bilgileri doğru ise. Neden API Key ve Secret Key kullanarak bir bearer token oluşturmak istiyorsunuz? User credential flow yerine, client credential flow ile mi ilerlemek istiyorsunuz?
Güzel faydalı bir paylaşım olmuş. Teşekkür ederiz. token kısmına illa bir süre vermek gerekir mi. ? Vermezsek bir sıkıntı yaratır mı. ? Saygılar.
Önerilen evet, vermeniz gerekmekte. Uzatabilmek için ise, refresh token implementasyonu kullanabilirsiniz. Maksat, eğer token sniff edilirse, kısa bir süre sonra otomatik olarak da expire olması.
öncelikle emeğinize sağlık, storedprocedurli model katmanına tanımladım ve conrolleri oradan gerçekleştiriyorum. farklı platformlar içinde bir api hazırladım ve ajaxla veri çekeceğim. model olarak ve storedprocedurum hazır autorization ile databasden login kontrolü nasıl yaparım ..teşekkürler
Merhaba, geç cevap için kusura bakmayın yoğun bir süreçteyim. Login için bir servis yazarak, “SimpleAuthorizationServerProvider” class’ı içerisindeki “GrantResourceOwnerCredentials” method’u içerisinden yapabilirsiniz.
Hocam merhaba, mobil uygulama için token based authentication yöntemi ile yazdığımız serviste logout işlemini nasıl yapabiliriz, yani bearer token’ının aktifliğini nasıl sonlandırabiliriz kullanıcının çıkış yaptıktan sonra yetkisi olmayan yerlere girmesini engellemek için doğru yol nedir ?
Merhaba, çok zor bir soru 🙂 Token lifetime’ını kısa verebilir, refresh token ile uzatabilirsiniz kullanıcı aktif olduğu sürece. Logout yaptığında da token’ı cihazdan silersiniz. Süresi geldiğinde de zaten token expire olacaktır. Bir diğer yaklaşım ise genelde, üretilen token’ları server tarafında persist edilmesi (redis gibi ortamda) ve valid olup olmadığının kontrol edilmesi. Bu yaklaşım çok hoşuma gitmese de, kesin çözüm oluyor.
Gayet güzel bir yazı, teşekkürler!
Öncelikle bu güzel paylaşım için teşekkürler. Yıllar olmuş ama hala faydalı insanlara. Tek eklemek istediğim şey, proje/properties/web/project Url kısmında, https.. ile başlayan url nin http ye döndülmesi gerekmekte. Neden bilmiyorum ama öyle çalışıyor postmanda.
Teşekkür ederim yorumunuz için, evet uzun zaman oldu. Faydalananlar olur umarım. 🙂
Yazı gayet anlaşılır olmuş aslında elinize sağlık. Peki hali hazırda bulunan bir apiye bearer token ile baglanmak istesek nasıl uygulayabiliriz? Bu konuda bir örnek üretebilirmisiniz?
Eğer yine identityserver kullanıyorsanız ilgili API tarafında da ilgili client library’lerini kullanarak configure edebilirsiniz. Bununla ilgili bir örnek de uygun vakitte yapmaya çalışırım. Eğer hala yardıma ihtiyacınız varsa tekrar yorum atabilirsiniz.
Merhabalar Gökhan Bey,
Ben bu sistemi kullanarak bir api authorize işlemi yaptım fakat merak ettiğim bir konu var.
Ben bir api yazarak ve bu api methoduna giriş yapan token ı gönderip o token in ne kadar süresi kaldığı bilgisine ulaşabilir miyim? aslında amacım aslında kişinin ne kadar süresi kaldığını görmek. bunu çerezlere vs kaydederek değilde direk api çağırır gibi çağırıp görebiliyor muyuz?
Merhaba, JWT shell’i olmadan tam istediğine ulaşabilir misin bilemedim ama bir kaç farklı yaklaşımı var. Normalde bu işlemi client’ın yönetmesi gerekir. Token’la beraber response üzerinde bildiğin gibi “expires_in” alanı bulunuyor. Bu alanı yöneterek, refresh token’ı kullanabilir client. Eğer direkt bearer yerine token’ı JWT ile çevrelersen, ozaman server tarafında da “expires_in” alanına ulaşabilirsin. JWT bunu “exp” olarak bir claim’e eklemektedir. Bir başka yöntem olarak da bearer in içindeki claim’lere kendin eklemeyi deneyebilirsin.
hocam yazilarinizi severek okuyorum cok sagolun. gecenlerde bir projede resimi formfile seklinde dondurdum apide goruyorum. ancak resimleri liste halinde bir kac resim donunce gorunteleri alamiyorum bununla alakali ornek bulabilecegim bir iceriginiz var mi baktim ancak goremedim veya bir tavsiyeniz olur mu? simdiden tesekkurler kolay gelsin 🙂
Merhaba teşekkür ederim yorumunuz için. Maalesef bahsettiğiniz tarzda bir örneğim yok…
Emeğine sağlık, hatasız çalıştı çok sağol.