ASP.NET Web API 2.2'de Tek Tek Hesaplar ve Yerel Oturum Açma ile Web API'lerinin güvenliğini sağlama
tarafından Mike Wasson
Bu konuda, üyelik veritabanında kimlik doğrulaması yapmak için OAuth2 kullanarak bir web API'sini güvenli hale getirmek gösterilmektedir.
Öğreticide kullanılan yazılım sürümleri
Visual Studio 2013'te Web API proje şablonu, kimlik doğrulaması için size üç seçenek sunar:
- Tek tek hesaplar. Uygulama bir üyelik veritabanı kullanır.
- Kuruluş hesapları. Kullanıcılar Azure Active Directory, Office 365 veya şirket içi Active Directory kimlik bilgileriyle oturum açar.
- Windows kimlik doğrulaması. Bu seçenek intranet uygulamalarına yöneliktir ve Windows Kimlik Doğrulaması IIS modülünü kullanır.
Tek tek hesaplar, kullanıcının oturum açması için iki yol sağlar:
- Yerel oturum açma. Kullanıcı siteye kaydolarak bir kullanıcı adı ve parola girer. Uygulama, parola karması üyelik veritabanında depolar. Kullanıcı oturum açtığında, ASP.NET Kimlik sistemi parolayı doğrular.
- Sosyal oturum açma. Kullanıcı Facebook, Microsoft veya Google gibi bir dış hizmetle oturum açar. Uygulama yine de üyelik veritabanında kullanıcı için bir girdi oluşturur, ancak herhangi bir kimlik bilgisi depolamaz. Kullanıcı, dış hizmette oturum açarak kimlik doğrulaması yapar.
Bu makalede yerel oturum açma senaryosuna bakabilirsiniz. Web API'sinde hem yerel hem de sosyal oturum açma bilgileri için isteklerin kimliğini doğrulamak için OAuth2 kullanılır. Ancak, kimlik bilgisi akışları yerel ve sosyal oturum açma için farklıdır.
Bu makalede, kullanıcının oturum açmasına ve kimliği doğrulanmış AJAX çağrılarını bir web API'sine göndermesine olanak tanıyan basit bir uygulama göstereceğim. Örnek kodu buradan indirebilirsiniz. Benioku, Visual Studio'da sıfırdan örneğin nasıl oluşturulacağını açıklar.
Örnek uygulama, veri bağlama için Knockout.js ve AJAX istekleri göndermek için jQuery kullanır. AJAX aramalarına odaklanacağım, bu yüzden bu makalenin Knockout.js bilmenize gerek yok.
Yol boyunca şunları açıklayacağım:
- Uygulamanın istemci tarafında yaptığı şey.
- Sunucuda neler oluyor?
- Ortadaki HTTP trafiği.
İlk olarak, bazı OAuth2 terminolojisini tanımlamamız gerekir.
- Kaynak. Korunabilecek bazı veriler.
- Kaynak sunucusu. Kaynağı barındıran sunucu.
- Kaynak sahibi. Kaynağa erişim izni verebilen varlık. (Genellikle kullanıcıdır.)
- İstemci: Kaynağa erişim isteyen uygulama. Bu makalede, istemci bir web tarayıcısıdır.
- Erişim belirteci. Bir kaynağa erişim izni veren belirteç.
- Taşıyıcı belirteci. Belirteci herkesin kullanabileceği özelliğiyle belirli bir erişim belirteci türü. Başka bir deyişle, bir istemcinin taşıyıcı belirteci kullanmak için şifreleme anahtarına veya başka bir gizli diziye ihtiyacı yoktur. Bu nedenle taşıyıcı belirteçlerin yalnızca HTTPS üzerinden kullanılması ve görece kısa süre sonu süreleri olması gerekir.
- Yetkilendirme sunucusu. Erişim belirteçleri veren bir sunucu.
Bir uygulama hem yetkilendirme sunucusu hem de kaynak sunucusu olarak görev yapabilir. Web API proje şablonu bu deseni izler.
Yerel Oturum Açma Kimlik Bilgisi Akışı
Yerel oturum açma için Web API'sinde OAuth2'de tanımlanan kaynak sahibi parola akışı kullanılır.
- Kullanıcı istemciye bir ad ve parola girer.
- İstemci bu kimlik bilgilerini yetkilendirme sunucusuna gönderir.
- Yetkilendirme sunucusu kimlik bilgilerinin kimliğini doğrular ve bir erişim belirteci döndürür.
- Korumalı bir kaynağa erişmek için istemci, HTTP isteğinin Yetkilendirme üst bilgisine erişim belirtecini ekler.
Web API proje şablonunda Bireysel hesaplar'ı seçtiğinizde, proje kullanıcı kimlik bilgilerini doğrulayan ve belirteçleri veren bir yetkilendirme sunucusu içerir. Aşağıdaki diyagramda, Web API bileşenleri açısından aynı kimlik bilgisi akışı gösterilmektedir.
Bu senaryoda, Web API denetleyicileri kaynak sunucuları gibi davranır. Kimlik doğrulama filtresi erişim belirteçlerini doğrular ve [Authorize] özniteliği bir kaynağı korumak için kullanılır. Bir denetleyici veya eylem [Authorize] özniteliğine sahip olduğunda, bu denetleyiciye veya eyleme yönelik tüm isteklerin kimliği doğrulanmalıdır. Aksi takdirde yetkilendirme reddedilir ve Web API'si 401 (Yetkisiz) hatası döndürür.
Yetkilendirme sunucusu ve kimlik doğrulama filtresi, OAuth2'nin ayrıntılarını işleyen bir OWIN ara yazılım bileşenine çağrır. Bu öğreticinin ilerleyen bölümlerinde tasarımı daha ayrıntılı olarak açıklayacağım.
Yetkisiz İstek Gönderme
Başlamak için uygulamayı çalıştırın ve Çağrı API'si düğmesine tıklayın. İstek tamamlandığında, Sonuç kutusunda bir hata iletisi görmeniz gerekir. Bunun nedeni, isteğin erişim belirteci içermemesidir, bu nedenle istek yetkisizdir.
ÇAĞRı API'si düğmesi~ /api/values öğesine bir AJAX isteği gönderir ve bu da bir Web API denetleyicisi eylemi çağırır. AJAX isteğini gönderen JavaScript kodunun bölümü aşağıdadır. Örnek uygulamada, tüm JavaScript uygulama kodu Scripts\app.js dosyasında bulunur.
// If we already have a bearer token, set the Authorization header.
var token = sessionStorage.getItem(tokenKey);
var headers = {};
if (token) {
headers.Authorization = 'Bearer ' + token;
}
$.ajax({
type: 'GET',
url: 'api/values/1',
headers: headers
}).done(function (data) {
self.result(data);
}).fail(showError);
Kullanıcı oturum açana kadar taşıyıcı belirteci ve dolayısıyla istekte Yetkilendirme üst bilgisi yoktur. Bu, isteğin 401 hatası döndürmesine neden olur.
HTTP isteği aşağıdadır. (Ben HTTP trafiğini yakalamak için Fiddler .)
GET https://localhost:44305/api/values HTTP/1.1
Host: localhost:44305
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; rv:32.0) Gecko/20100101 Firefox/32.0
Accept: */*
Accept-Language: en-US,en;q=0.5
X-Requested-With: XMLHttpRequest
Referer: https://localhost:44305/
HTTP yanıtı:
HTTP/1.1 401 Unauthorized
Content-Type: application/json; charset=utf-8
Server: Microsoft-IIS/8.0
WWW-Authenticate: Bearer
Date: Tue, 30 Sep 2014 21:54:43 GMT
Content-Length: 61
{"Message":"Authorization has been denied for this request."}
Yanıtın, sınama taşıyıcı olarak ayarlanmış bir Www-Authenticate üst bilgisi içerdiğine dikkat edin. Bu, sunucunun taşıyıcı belirteç beklediğini gösterir.
Kullanıcı Kaydetme
Uygulamanın Kaydet bölümünde bir e-posta ve parola girin ve Kaydet düğmesine tıklayın.
Bu örnek için geçerli bir e-posta adresi kullanmanız gerekmez, ancak gerçek bir uygulama adresi onaylar. (Bkz. Oturum açma, e-posta onayı ve parola sıfırlama ile güvenli bir ASP.NET MVC 5 web uygulaması oluşturun.) Parola için büyük harf, küçük harf, sayı ve alfasayısal olmayan karakter içeren "Parola1!" gibi bir değer kullanın. Uygulamayı basit tutmak için istemci tarafı doğrulamasını atladığım için parola biçimiyle ilgili bir sorun varsa 400 (Hatalı İstek) hatası alırsınız.
Kaydet düğmesi ~/api/Account/Register/ adresine bir POST isteği gönderir. İstek gövdesi, adı ve parolayı tutan bir JSON nesnesidir. İsteği gönderen JavaScript kodu aşağıdadır:
var data = {
Email: self.registerEmail(),
Password: self.registerPassword(),
ConfirmPassword: self.registerPassword2()
};
$.ajax({
type: 'POST',
url: '/api/Account/Register',
contentType: 'application/json; charset=utf-8',
data: JSON.stringify(data)
}).done(function (data) {
self.result("Done!");
}).fail(showError);
HTTP isteği, burada $CREDENTIAL_PLACEHOLDER$
parola anahtar-değer çifti için bir yer tutucudur:
POST https://localhost:44305/api/Account/Register HTTP/1.1
Host: localhost:44305
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; rv:32.0) Gecko/20100101 Firefox/32.0
Accept: */*
Content-Type: application/json; charset=utf-8
X-Requested-With: XMLHttpRequest
Referer: https://localhost:44305/
Content-Length: 84
{"Email":"alice@example.com",$CREDENTIAL_PLACEHOLDER1$,$CREDENTIAL_PLACEHOLDER2$"}
HTTP yanıtı:
HTTP/1.1 200 OK
Server: Microsoft-IIS/8.0
Date: Wed, 01 Oct 2014 00:57:58 GMT
Content-Length: 0
Bu istek sınıfı tarafından AccountController
işlenir. Dahili olarak, AccountController
üyelik veritabanını yönetmek için ASP.NET Identity kullanır.
Uygulamayı Visual Studio'dan yerel olarak çalıştırırsanız, kullanıcı hesapları AspNetUsers tablosundaki LocalDB'de depolanır. Visual Studio'da tabloları görüntülemek için Görünüm menüsüne tıklayın, Sunucu Gezgini'ni seçin ve veri bağlantıları'nı genişletin.
Erişim Belirteci Alma
Şu ana kadar herhangi bir OAuth işlemi gerçekleştirmedik, ancak şimdi erişim belirteci istediğimizde OAuth yetkilendirme sunucusunu çalışırken göreceğiz. Örnek uygulamanın Oturum Aç alanına e-postayı ve parolayı girin ve Oturum Aç'a tıklayın.
Oturum Aç düğmesi belirteç uç noktasına bir istek gönderir. İsteğin gövdesi aşağıdaki form-url ile kodlanmış verileri içerir:
- grant_type: "parola"
- kullanıcı adı: <kullanıcının e-posta adresi>
- parola: <parola>
AJAX isteğini gönderen JavaScript kodu aşağıdadır:
var loginData = {
grant_type: 'password',
username: self.loginEmail(),
password: self.loginPassword()
};
$.ajax({
type: 'POST',
url: '/Token',
data: loginData
}).done(function (data) {
self.user(data.userName);
// Cache the access token in session storage.
sessionStorage.setItem(tokenKey, data.access_token);
}).fail(showError);
İstek başarılı olursa, yetkilendirme sunucusu yanıt gövdesinde bir erişim belirteci döndürür. Belirteci daha sonra API'ye istek gönderirken kullanmak üzere oturum depolama alanında depoladığımıza dikkat edin. Bazı kimlik doğrulama biçimlerinden (tanımlama bilgisi tabanlı kimlik doğrulaması gibi) farklı olarak tarayıcı, erişim belirtecini sonraki isteklere otomatik olarak eklemez. Uygulamanın bunu açıkça yapması gerekir. Bu iyi bir şey, çünkü CSRF güvenlik açıklarını sınırlar.
HTTP isteği:
POST https://localhost:44305/Token HTTP/1.1
Host: localhost:44305
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; rv:32.0) Gecko/20100101 Firefox/32.0
Accept: */*
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With: XMLHttpRequest
Referer: https://localhost:44305/
Content-Length: 68
grant_type=password&username=alice%40example.com&password=Password1!
İsteğin kullanıcının kimlik bilgilerini içerdiğini görebilirsiniz. Aktarım katmanı güvenliği sağlamak için HTTPS kullanmalısınız.
HTTP yanıtı:
HTTP/1.1 200 OK
Content-Length: 669
Content-Type: application/json;charset=UTF-8
Server: Microsoft-IIS/8.0
Date: Wed, 01 Oct 2014 01:22:36 GMT
{
"access_token":"imSXTs2OqSrGWzsFQhIXziFCO3rF...",
"token_type":"bearer",
"expires_in":1209599,
"userName":"alice@example.com",
".issued":"Wed, 01 Oct 2014 01:22:33 GMT",
".expires":"Wed, 15 Oct 2014 01:22:33 GMT"
}
Okunabilirlik için JSON'u girintilendirdim ve erişim belirtecini keserek oldukça uzun bir süre kullandım.
access_token
, token_type
ve expires_in
özellikleri OAuth2 belirtimi tarafından tanımlanır. Diğer özellikler (userName
, .issued
ve .expires
) yalnızca bilgilendirme amaçlıdır. Yönteminde bu ek özellikleri TokenEndpoint
ekleyen kodu /Providers/ApplicationOAuthProvider.cs dosyasında bulabilirsiniz.
Kimliği Doğrulanmış İstek Gönderme
Taşıyıcı belirtecimiz olduğuna göre API'ye kimliği doğrulanmış bir istekte bulunabiliriz. Bu, istekte Yetkilendirme üst bilgisi ayarlanarak yapılır. Bunu görmek için API'yi ara düğmesine yeniden tıklayın.
HTTP isteği:
GET https://localhost:44305/api/values/1 HTTP/1.1
Host: localhost:44305
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; rv:32.0) Gecko/20100101 Firefox/32.0
Accept: */*
Authorization: Bearer imSXTs2OqSrGWzsFQhIXziFCO3rF...
X-Requested-With: XMLHttpRequest
HTTP yanıtı:
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Server: Microsoft-IIS/8.0
Date: Wed, 01 Oct 2014 01:41:29 GMT
Content-Length: 27
"Hello, alice@example.com."
Oturumu Kapat
Tarayıcı kimlik bilgilerini veya erişim belirtecini önbelleğe almadığından oturumu kapatma işlemi, belirteci oturum depolama alanından kaldırarak "unutma" işlemidir:
self.logout = function () {
sessionStorage.removeItem(tokenKey)
}
Bireysel Hesaplar Proje Şablonunu Anlama
ASP.NET Web Uygulaması proje şablonunda Tek Tek Hesaplar'ı seçtiğinizde proje şunları içerir:
- OAuth2 yetkilendirme sunucusu.
- Kullanıcı hesaplarını yönetmek için bir Web API uç noktası
- Kullanıcı hesaplarını depolamak için bir EF modeli.
Bu özellikleri uygulayan ana uygulama sınıfları şunlardır:
AccountController
. Kullanıcı hesaplarını yönetmek için bir Web API uç noktası sağlar. EylemRegister
, bu öğreticide kullandığımız tek eylemdir. Sınıftaki diğer yöntemler parola sıfırlamayı, sosyal oturum açma bilgilerini ve diğer işlevleri destekler.ApplicationUser
, /Models/IdentityModels.cs içinde tanımlanır. Bu sınıf, üyelik veritabanındaki kullanıcı hesapları için EF modelidir.ApplicationUserManager
, /App_Start/IdentityConfig.cs içinde tanımlanır Bu sınıf UserManager'dan türetilir ve kullanıcı hesaplarında yeni kullanıcı oluşturma, parolaları doğrulama vb. işlemler gerçekleştirir ve değişiklikleri veritabanında otomatik olarak kalıcı hale getirir.ApplicationOAuthProvider
. Bu nesne OWIN ara yazılımına takılır ve ara yazılım tarafından tetiklenen olayları işler. OAuthAuthorizationServerProvider'dan türetilir.
Yetkilendirme Sunucusunu Yapılandırma
StartupAuth.cs'da, aşağıdaki kod OAuth2 yetkilendirme sunucusunu yapılandırıyor.
PublicClientId = "self";
OAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/Token"),
Provider = new ApplicationOAuthProvider(PublicClientId),
AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
// Note: Remove the following line before you deploy to production:
AllowInsecureHttp = true
};
// Enable the application to use bearer tokens to authenticate users
app.UseOAuthBearerTokens(OAuthOptions);
TokenEndpointPath
özelliği, yetkilendirme sunucusu uç noktasının URL yoludur. Bu, uygulamanın taşıyıcı belirteçleri almak için kullandığı URL'dir.
özelliği, Provider
OWIN ara yazılımına takılan ve ara yazılım tarafından tetiklenen olayları işleyen bir sağlayıcı belirtir.
Uygulama belirteç almak istediğinde temel akış aşağıdadır:
- Uygulama, erişim belirteci almak için ~/Token'a bir istek gönderir.
- OAuth ara yazılımı sağlayıcıyı çağırır
GrantResourceOwnerCredentials
. - Sağlayıcı kimlik bilgilerini doğrulamak ve bir talep kimliği oluşturmak için öğesini çağırır
ApplicationUserManager
. - Bu başarılı olursa, sağlayıcı belirteci oluşturmak için kullanılan bir kimlik doğrulama bileti oluşturur.
OAuth ara yazılımı kullanıcı hesapları hakkında hiçbir şey bilmiyor. Sağlayıcı ara yazılım ile ASP.NET Kimliği arasında iletişim kurar. Yetkilendirme sunucusunu uygulama hakkında daha fazla bilgi için bkz . OWIN OAuth 2.0 Yetkilendirme Sunucusu.
Web API'sini Taşıyıcı Belirteçlerini kullanacak şekilde yapılandırma
yönteminde WebApiConfig.Register
, aşağıdaki kod Web API işlem hattı için kimlik doğrulamasını ayarlar:
config.SuppressDefaultHostAuthentication();
config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
HostAuthenticationFilter sınıfı taşıyıcı belirteçleri kullanarak kimlik doğrulamasını etkinleştirir.
SuppressDefaultHostAuthentication yöntemi, Web API'sine istek Web API'si işlem hattına ulaşmadan önce iis veya OWIN ara yazılımı tarafından gerçekleşen kimlik doğrulamalarını yoksayması gerektiğini bildirir. Bu şekilde Web API'sini yalnızca taşıyıcı belirteçleri kullanarak kimlik doğrulamasıyla kısıtlayabiliriz.
Not
Özellikle, uygulamanızın MVC bölümü kimlik bilgilerini tanımlama bilgisinde depolayan form kimlik doğrulamasını kullanabilir. Tanımlama bilgisi tabanlı kimlik doğrulaması, CSRF saldırılarını önlemek için sahteciliğe karşı koruma belirteçlerinin kullanılmasını gerektirir. Web API'sinin sahteciliğe karşı koruma belirtecini istemciye göndermesinin uygun bir yolu olmadığından, bu web API'leri için bir sorundur. (Bu sorunla ilgili daha fazla arka plan için bkz.Web API'sinde CSRF Saldırılarını Önleme.) SuppressDefaultHostAuthentication çağrısı, Web API'lerinin tanımlama bilgilerinde depolanan kimlik bilgilerinden gelen CSRF saldırılarına karşı savunmasız olmamasını sağlar.
İstemci korumalı bir kaynak istediğinde, Web API işlem hattında şunlar olur:
- HostAuthentication filtresi, belirteci doğrulamak için OAuth ara yazılımını çağırır.
- Ara yazılım belirteci talep kimliğine dönüştürür.
- Bu noktada isteğin kimliği doğrulanır ancak yetkilendirilmemiş olur.
- Yetkilendirme filtresi talep kimliğini inceler. Talepler kullanıcıyı bu kaynak için yetkilendiriyorsa, istek yetkilendirilmiştir. Varsayılan olarak, [Authorize] özniteliği kimliği doğrulanmış tüm istekleri yetkilendir. Ancak, role veya diğer taleplere göre yetkilendirme yapabilirsiniz. Daha fazla bilgi için bkz . Web API'sinde Kimlik Doğrulaması ve Yetkilendirme.
- Önceki adımlar başarılı olursa denetleyici korumalı kaynağı döndürür. Aksi takdirde, istemci bir 401 (Yetkisiz) hatası alır.
Ek Kaynaklar
- ASP.NET Kimliği
- VS2013 RC için SPA Şablonundaki Güvenlik Özelliklerini Anlama. MSDN blog gönderisi: Hongye Sun.
- Web API'sinin Bireysel Hesaplar Şablonunu Parçalara Ayırma–Bölüm 2: Yerel Hesaplar. Dominick Baier tarafından blog gönderisi.
- OWIN ile konak kimlik doğrulaması ve Web API'si. Brock Allen'ın ve'nin
SuppressDefaultHostAuthentication
HostAuthenticationFilter
iyi bir açıklaması. - VS 2013 şablonlarında ASP.NET Kimliği'nde profil bilgilerini özelleştirme. Pranav Rastogi tarafından gönderilen MSDN blog gönderisi.
- ASP.NET Identity'de UserManager sınıfı için istek ömrü yönetimi başına. Suhas Joshi'nin msdn blog gönderisi, sınıfın
UserManager
iyi bir açıklamasıyla.