Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
készítette: Mike Wasson
Ez a témakör bemutatja, hogyan lehet biztonságossá tenni egy webes API-t az OAuth2 használatával a tagsági adatbázison való hitelesítéshez.
Az oktatóanyagban használt szoftververziók
A Visual Studio 2013-ban a Webes API-projektsablon három hitelesítési lehetőséget kínál:
- Egyéni fiókok. Az alkalmazás tagsági adatbázist használ.
- Szervezeti fiókok. A felhasználók az Azure Active Directory, az Office 365 vagy a helyszíni Active Directory hitelesítő adataikkal jelentkeznek be.
- Windows-hitelesítés. Ez a beállítás intranetes alkalmazásokhoz készült, és a Windows Authentication IIS modult használja.
A felhasználók az egyes fiókjaikba kétféleképpen jelentkezhetnek be.
- helyi bejelentkezés. A felhasználó regisztrál a webhelyen, és megadja a felhasználónevet és a jelszót. Az alkalmazás a jelszókivonatot a tagsági adatbázisban tárolja. Amikor a felhasználó bejelentkezik, a ASP.NET identitásrendszer ellenőrzi a jelszót.
- közösségi bejelentkezés. A felhasználó egy külső szolgáltatással, például a Facebookkal, a Microsofttal vagy a Google-jal jelentkezik be. Az alkalmazás továbbra is létrehoz egy bejegyzést a felhasználó számára a tagsági adatbázisban, de nem tárol hitelesítő adatokat. A felhasználó a külső szolgáltatásba való bejelentkezéssel hitelesít.
Ez a cikk a helyi bejelentkezési forgatókönyvet ismerteti. A helyi és a közösségi bejelentkezéshez a Web API az OAuth2 használatával hitelesíti a kéréseket. A hitelesítő adatok folyamatai azonban eltérnek a helyi és a közösségi bejelentkezéshez.
Ebben a cikkben bemutatok egy egyszerű alkalmazást, amellyel a felhasználó bejelentkezhet, és hitelesített AJAX-hívásokat küldhet egy webes API-nak. A mintakódot itt töltheti le . A readme leírja, hogyan lehet létrehozni a mintát a semmiből a Visual Studióban.
A mintaalkalmazás Knockout.js használ adatkötéshez és jQuery-hez az AJAX-kérések küldéséhez. Az AJAX-hívásokra összpontosítok, ezért nem kell ismernie a Knockout.js-t ehhez a cikkhez.
Az út során a következőt írom le:
- Az alkalmazás feladata az ügyféloldalon.
- Mi történik a kiszolgálón?
- A HTTP-forgalom középen.
Először meg kell határoznunk néhány OAuth2-terminológiát.
- erőforrás. Néhány adat, amely védhető.
- erőforráskiszolgáló. Az erőforrást üzemeltető kiszolgáló.
- erőforrás tulajdonosa. Az az entitás, amely engedélyt adhat egy erőforrás elérésére. (Általában a felhasználó.)
- ügyfél: Az az alkalmazás, amely hozzá szeretne férni az erőforráshoz. Ebben a cikkben az ügyfél egy webböngésző.
- Hozzáférési jogkivonat. Egy erőforráshoz hozzáférést biztosító jogkivonat.
- Tulajdonosi jogkivonat. A hozzáférési jogkivonat egy adott típusa, amelynek tulajdonságát bárki használhatja. Más szóval az ügyfélnek nincs szüksége titkosítási kulcsra vagy más titkos kulcsra a tulajdonosi jogkivonat használatához. Ezért a tulajdonosi jogkivonatokat csak HTTPS-en keresztül szabad használni, és viszonylag rövid lejárati idővel kell rendelkezniük.
- engedélyezési kiszolgáló. Egy kiszolgáló, amely hozzáférési jogkivonatokat ad ki.
Az alkalmazások engedélyezési kiszolgálóként és erőforrás-kiszolgálóként is működhetnek. A Webes API-projektsablon ezt a mintát követi.
Helyi bejelentkezési hitelesítőadat-folyamat
A helyi bejelentkezéshez a Webes API az OAuth2-ben definiált erőforrás-tulajdonosi jelszófolyamatot használja.
- A felhasználó nevet és jelszót ad meg az ügyfélnek.
- Az ügyfél elküldi ezeket a hitelesítő adatokat az engedélyezési kiszolgálónak.
- Az engedélyezési kiszolgáló hitelesíti a hitelesítő adatokat, és visszaad egy hozzáférési jogkivonatot.
- Védett erőforrás eléréséhez az ügyfél a HTTP-kérés Engedélyezési fejlécében tartalmazza a hozzáférési jogkivonatot.
Amikor a Egyéni fiókokat választja a Web API projekt sablonban, a projekt tartalmaz egy engedélyezési kiszolgálót, amely ellenőrzi a felhasználói hitelesítő adatokat, és tokeneket ad ki. Az alábbi ábra ugyanazt a hitelesítőadat-folyamatot mutatja be a webes API-összetevők tekintetében.
Ebben a forgatókönyvben a webes API-vezérlők erőforrás-kiszolgálókként működnek. A hitelesítési szűrő ellenőrzi a hozzáférési jogkivonatokat, és az [Engedélyezés] attribútumot használják az erőforrások védelmére. Ha egy vezérlő vagy művelet rendelkezik az [Engedélyezés] attribútummal, az adott vezérlőhöz vagy művelethez érkező összes kérést hitelesíteni kell. Ellenkező esetben a rendszer megtagadja az engedélyezést, és a Web API 401-es (jogosulatlan) hibát ad vissza.
Az engedélyezési kiszolgáló és a hitelesítési szűrő egyaránt meghív egy OWIN köztes szoftver összetevőbe, amely az OAuth2 részleteit kezeli. Az oktatóanyag későbbi részében részletesebben is bemutatom a tervet.
Jogosulatlan kérés küldése
Első lépésként futtassa az alkalmazást, és kattintson a Call API gombra. Amikor a kérés befejeződik, hibaüzenet jelenik meg az Eredmény mezőben. Ennek az az oka, hogy a kérelem nem tartalmaz hozzáférési jogkivonatot, ezért a kérés jogosulatlan.
A Call API gomb egy AJAX-kérést küld a ~/api/values címre, amely webes API-vezérlőműveletet hív meg. Itt található az AJAX-kérést küldő JavaScript-kód szakasza. A mintaalkalmazásban az összes JavaScript-alkalmazáskód a Szkriptek\app.js fájlban található.
// 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);
Amíg a felhasználó be nem jelentkezik, nincs tulajdonosi jogkivonat, ezért nincs engedélyezési fejléc a kérelemben. Emiatt a kérés 401-et eredményez.
Itt található a HTTP-kérés. (Fiddler használtam a HTTP-forgalom rögzítéséhez.)
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-válasz:
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."}
Figyelje meg, hogy a válasz tartalmaz egy Www-Authenticate fejlécet, amelyben a kihívás a Bearer értékre van beállítva. Ez azt jelzi, hogy a kiszolgáló hordozó tokent vár.
Felhasználó regisztrálása
Az alkalmazás Regisztrálás szakaszában adjon meg egy e-mailt és egy jelszót, majd kattintson a Regisztrálás gombra.
Ehhez a mintához nem kell érvényes e-mail-címet használnia, de egy valódi alkalmazás megerősítené a címet. (Lásd: Biztonságos ASP.NET MVC 5 webalkalmazás létrehozása bejelentkezéssel, e-mail-megerősítéssel és jelszó-visszaállítással.) A jelszóhoz használjon valami hasonlót: "Jelszó1!", nagybetűvel, kisbetűvel, számmal és nem alfa-numerikus karakterrel. Az alkalmazás egyszerűségéhez kihagytam az ügyféloldali érvényesítést, így ha probléma van a jelszóformátummal, 400 -os (hibás kérelem) hibaüzenet jelenik meg.
A Regisztrálás gomb post kérést küld a ~/api/Account/Register/címre. A kérelem törzse egy JSON-objektum, amely tartalmazza a nevet és a jelszót. Itt található a kérést küldő JavaScript-kód:
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-kérés, ahol $CREDENTIAL_PLACEHOLDER$ a jelszókulcs-érték pár helyőrzője:
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-válasz:
HTTP/1.1 200 OK
Server: Microsoft-IIS/8.0
Date: Wed, 01 Oct 2014 00:57:58 GMT
Content-Length: 0
Ezt a kérést a AccountController osztály kezeli. Belsőleg a AccountController ASP.NET Identity használatával kezeli a tagsági adatbázist.
Ha az alkalmazást helyileg futtatja a Visual Studióból, a felhasználói fiókok a LocalDB-ben, az AspNetUsers táblában lesznek tárolva. A Táblák Visual Studióban való megtekintéséhez kattintson a Nézet menüre, válassza Kiszolgálókezelőlehetőséget, majd bontsa ki adatkapcsolatok.
Hozzáférési jogkivonat lekérése
Eddig nem végeztünk OAuth-hitelesítést, de most működés közben látni fogjuk az OAuth engedélyezési kiszolgálót, amikor hozzáférési jogkivonatot kérünk. A mintaalkalmazás Bejelentkezés területén adja meg az e-mailt és a jelszót, majd kattintson Bejelentkezésgombra.
A Bejelentkezés gomb kérést küld a token végpontra. A kérelem törzse az alábbi űrlap-URL-kódolású adatokat tartalmazza:
- grant_type: "jelszó"
- felhasználónév: <a felhasználó e-mailje:>
- jelszó: <jelszó>
Itt található az AJAX-kérést küldő JavaScript-kód:
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);
Ha a kérés sikeres, az engedélyezési kiszolgáló egy hozzáférési jogkivonatot ad vissza a válasz törzsében. Figyelje meg, hogy a jogkivonatot munkamenet-tárolóban tároljuk, hogy később használhassuk, amikor kéréseket küldünk az API-nak. A hitelesítés egyes formáival (például a cookie-alapú hitelesítéssel) ellentétben a böngésző nem fogja automatikusan belefoglalni a hozzáférési jogkivonatot a későbbi kérésekbe. Az alkalmazásnak kifejezetten ezt kell tennie. Ez jó dolog, mert korlátozza CSRF biztonsági réseit.
HTTP-kérés:
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!
Láthatja, hogy a kérelem tartalmazza a felhasználó hitelesítő adatait. Az átviteli réteg biztonságának biztosításához https kell használnia.
HTTP-válasz:
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"
}
Az olvashatóság érdekében behúztam a JSON-t, és csonkoltam a hozzáférési jogkivonatot, amely meglehetősen hosszú.
A access_token, token_typeés expires_in tulajdonságait az OAuth2 specifikáció határozza meg. A többi tulajdonság (userName, .issuedés .expires) csak tájékoztató jellegűek. A további tulajdonságokat hozzáadó kódot a /Providers/ApplicationOAuthProvider.cs fájlban, a TokenEndpoint metódusban találja.
Hitelesített kérelem küldése
Most, hogy rendelkezünk egy tulajdonosi jogkivonattal, hitelesíthetjük a kérést az API-hoz. Ez a kérelem engedélyezési fejlécének beállításával végezhető el. Kattintson ismét a Call API gombra, hogy ezt láthassa.
HTTP-kérés:
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-válasz:
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."
Kijelentkezés
Mivel a böngésző nem gyorsítótárazza a hitelesítő adatokat vagy a hozzáférési jogkivonatot, a kijelentkezés egyszerűen a jogkivonat "elfelejtéséről" szól, ha eltávolítja azt a munkamenet-tárolóból:
self.logout = function () {
sessionStorage.removeItem(tokenKey)
}
Az egyes fiókok projektsablonjának ismertetése
Amikor az ASP.NET webalkalmazás projektsablonjában az Egyes fiókok lehetőséget választja, a projekt a következőket foglalja magában:
- OAuth2 engedélyezési kiszolgáló.
- Webes API-végpont felhasználói fiókok kezeléséhez
- A felhasználói fiókok tárolására szolgáló EF-modell.
Az alábbi funkciókat megvalósító fő alkalmazásosztályok:
-
AccountController. Webes API-végpontot biztosít a felhasználói fiókok kezeléséhez. ARegisterművelet az egyetlen, amelyet ebben az oktatóanyagban használtunk. Az osztály egyéb módszerei támogatják a jelszó-visszaállítást, a közösségi bejelentkezéseket és más funkciókat. -
ApplicationUser, definiálva a /Models/IdentityModels.cs. Ez az osztály a tagsági adatbázisban lévő felhasználói fiókok EF-modellje. -
ApplicationUserManagera /App_Start/IdentityConfig.cs fájlban van definiálva. Ez az osztály a UserManager osztályból származik, és műveleteket végez a felhasználói fiókokon, például létrehoz egy új felhasználót, ellenőrzi a jelszavakat stb.; az adatbázis változásait pedig automatikusan menti. -
ApplicationOAuthProvider. Ez az objektum az OWIN köztes szoftverhez csatlakozik, és feldolgozza a köztes szoftver által kiváltott eseményeket. Ez a OAuthAuthorizationServerProvideralapján működik.
Az engedélyezési kiszolgáló konfigurálása
A StartupAuth.cs az alábbi kód konfigurálja az OAuth2 engedélyezési kiszolgálót.
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);
A TokenEndpointPath tulajdonság az engedélyezési kiszolgáló végpontjának URL-címe. Az alkalmazás ezt az URL-címet használja a tulajdonosi jogkivonatok lekéréséhez.
A Provider tulajdonság egy olyan szolgáltatót határoz meg, amely az OWIN köztes szoftverhez csatlakozik, és feldolgozza a köztes szoftver által kiváltott eseményeket.
Az alapvető folyamat, amikor az alkalmazás egy token-t szeretne lekérni, a következő:
- Hozzáférési jogkivonat lekéréséhez az alkalmazás kérést küld a ~/Token címre.
- Az OAuth köztes szoftver meghívja
GrantResourceOwnerCredentials-t a szolgáltatónál. - A szolgáltató hívja a
ApplicationUserManager-t, hogy ellenőrizze a hitelesítő adatokat és létrehozzon egy igényidentitást. - Ha ez sikerül, a szolgáltató létrehoz egy hitelesítési jegyet, amely a token létrehozásához használatos.
Az OAuth köztes szoftver nem tud semmit a felhasználói fiókokról. A szolgáltató kommunikál a köztes szoftver és a ASP.NET Identitás között. Az engedélyezési kiszolgáló implementálásával kapcsolatos további információkért lásd OWIN OAuth 2.0 engedélyezési kiszolgáló.
A Webes API konfigurálása a Megbízó tokenek használatára
A WebApiConfig.Register metódusban a következő kód állítja be a webes API-folyamat hitelesítését:
config.SuppressDefaultHostAuthentication();
config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
A HostAuthenticationFilter osztály engedélyezi a hitelesítést bearer tokenekkel.
A SuppressDefaultHostAuthentication metódus arra utasítja a Web API-t, hogy hagyja figyelmen kívül azokat a hitelesítéseket, amelyek azelőtt történnek, hogy a kérés elérné a Webes API-folyamatot, akár IIS, akár OWIN köztes szoftver használatával. Így korlátozhatjuk, hogy a Webes API csak tulajdonosi jogkivonatok használatával hitelesítsen.
Jegyzet
Az alkalmazás MVC-része űrlaphitelesítést használhat, amely a hitelesítő adatokat egy cookie-ban tárolja. A cookie-alapú hitelesítéshez hamisítás elleni jogkivonatok használata szükséges a CSRF-támadások megelőzése érdekében. Ez problémát jelent a webes API-k esetében, mert a webes API nem kényelmesen küldheti el a hamisítás elleni jogkivonatot az ügyfélnek. (A probléma hátteréről további információt a CsRF-támadások megakadályozása a Webes API-bancímű témakörben talál.) A SuppressDefaultHostAuthentication hívásával biztosítható, hogy a Web API ne legyen sebezhető a cookie-kban tárolt hitelesítő adatok CSRF-támadásai ellen.
Amikor az ügyfél védett erőforrást kér, a web API-folyamat az alábbi módon történik:
- A HostAuthentication szűrő meghívja az OAuth köztes szoftvert a jogkivonat érvényesítéséhez.
- A köztes szoftver jogcím-identitássá alakítja a jogkivonatot.
- A kérés jelenleg hitelesített de nem engedélyezett.
- Az engedélyezési szűrő megvizsgálja a jogcím-identitást. Ha a jogcímek engedélyezik a felhasználó számára az erőforrást, a kérés engedélyezve van. Alapértelmezés szerint az [Engedélyezés] attribútum engedélyezi a hitelesített kéréseket. Azonban engedélyezheti szerepkör vagy más jogcímek alapján. További információ: Hitelesítés és engedélyezés a Webes API-ban.
- Ha az előző lépések sikeresek, a vezérlő visszaadja a védett erőforrást. Ellenkező esetben az ügyfél 401(jogosulatlan) hibaüzenetet kap.
További erőforrások
- ASP.NET Identitás
- A VS2013 RCSPA-sablonjának biztonsági funkcióinak ismertetése. MSDN blogbejegyzés Hongye Sun.
- A Webes API egyéni fióksablonjának disszecting(2) rész: Helyi fiókok. Blogbejegyzés: Dominick Baier.
- hu-HU: Gazdagép-hitelesítés és webes API OWIN-nel. Brock Allen
SuppressDefaultHostAuthenticationésHostAuthenticationFilterjó magyarázata. - Profiladatok testreszabása az ASP.NET Identity-ben a VS 2013 sablonjaiban. Az MSDN blogbejegyzés Pranav Rastogi.
-
Kérelemenkénti élettartam-kezelés az ASP.NET IdentityUserManager osztályához. MSDN blogbejegyzés Suhas Joshi tollából, amely jól magyarázza a
UserManagerosztályt.