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
A hitelesítési szűrő egy HTTP-kérést hitelesítő összetevő. A Web API 2 és az MVC 5 egyaránt támogatja a hitelesítési szűrőket, de kissé eltérnek, főként a szűrőfelület elnevezési konvencióiban. Ez a témakör a webes API hitelesítési szűrőit ismerteti.
A hitelesítési szűrők lehetővé teszik az egyes vezérlők vagy műveletek hitelesítési sémájának beállítását. Így az alkalmazás különböző HITELESÍTÉSI mechanizmusokat támogat a különböző HTTP-erőforrásokhoz.
Ebben a cikkben az alapszintű hitelesítési mintából származó kódot mutatom be a következőn https://github.com/aspnet/samples: . A minta egy hitelesítési szűrőt mutat be, amely implementálja a HTTP Basic Access Authentication sémát (RFC 2617). A szűrő egy IdentityBasicAuthenticationAttribute nevű osztályban van megvalósítva. Nem jelenítem meg a mintából származó összes kódot, csak azokat a részeket, amelyek bemutatják, hogyan kell hitelesítési szűrőt írni.
Hitelesítési szűrő beállítása
A többi szűrőhöz hasonlóan a hitelesítési szűrők is alkalmazhatók vezérlőnként, műveletenként vagy globálisan az összes webes API-vezérlőre.
Ha hitelesítési szűrőt szeretne alkalmazni egy vezérlőre, díszítse a vezérlőosztályt a szűrőattribútummal. Az alábbi kód beállítja a [IdentityBasicAuthentication] szűrőt egy vezérlőosztályra, amely lehetővé teszi az alapszintű hitelesítést a vezérlő összes műveletéhez.
[IdentityBasicAuthentication] // Enable Basic authentication for this controller.
[Authorize] // Require authenticated requests.
public class HomeController : ApiController
{
public IHttpActionResult Get() { . . . }
public IHttpActionResult Post() { . . . }
}
Ha a szűrőt egy műveletre szeretné alkalmazni, díszítse a műveletet a szűrővel. Az alábbi kód beállítja a szűrőt [IdentityBasicAuthentication] a vezérlő metódusára Post .
[Authorize] // Require authenticated requests.
public class HomeController : ApiController
{
public IHttpActionResult Get() { . . . }
[IdentityBasicAuthentication] // Enable Basic authentication for this action.
public IHttpActionResult Post() { . . . }
}
Ha a szűrőt minden webes API-vezérlőre alkalmazni szeretné, adja hozzá a GlobalConfiguration.Filters szolgáltatáshoz.
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Filters.Add(new IdentityBasicAuthenticationAttribute());
// Other configuration code not shown...
}
}
Webes API-hitelesítési szűrő implementálása
A Webes API-ban a hitelesítési szűrők implementálják a System.Web.Http.Filters.IAuthenticationFilter felületet. A System.Attribútumtól is örökölniük kell őket, hogy attribútumként legyenek alkalmazva.
Az IAuthenticationFilter interfész két módszerrel rendelkezik:
- Az AuthenticateAsync hitelesíti a kérést a kérelem hitelesítő adatainak hitelesítésével, ha vannak ilyenek.
- A ChallengeAsync szükség esetén hitelesítési kihívást ad a HTTP-válaszhoz.
Ezek a metódusok megfelelnek az RFC 2612-ben és az RFC2617-ben definiált hitelesítési folyamatnak:
- Az ügyfél hitelesítő adatokat küld az Engedélyezés fejlécben. Ez általában akkor fordul elő, ha az ügyfél 401 (jogosulatlan) választ kap a kiszolgálótól. Az ügyfél azonban bármilyen kéréssel küldhet hitelesítő adatokat, nem csak a 401-et lekérése után.
- Ha a kiszolgáló nem fogadja el a hitelesítő adatokat, a rendszer 401(Jogosulatlan) választ ad vissza. A válasz tartalmaz egy Www-Authenticate fejlécet, amely egy vagy több kihívást tartalmaz. Minden feladat egy, a kiszolgáló által felismert hitelesítési sémát határoz meg.
A kiszolgáló a 401-et névtelen kérésből is visszaadhatja. Valójában a hitelesítési folyamat általában így indul el:
- Az ügyfél névtelen kérést küld.
- A kiszolgáló a 401-et adja vissza.
- Az ügyfelek hitelesítő adatokkal újraküldik a kérést.
Ez a folyamat mind a hitelesítési , mind az engedélyezési lépéseket tartalmazza.
- A hitelesítés igazolja az ügyfél identitását.
- Az engedélyezés határozza meg, hogy az ügyfél hozzáfér-e egy adott erőforráshoz.
A Webes API-ban a hitelesítési szűrők kezelik a hitelesítést, de az engedélyezést nem. Az engedélyezést egy engedélyezési szűrővel vagy a vezérlőműveleten belül kell elvégezni.
A Web API 2 folyamatának folyamata a következő:
- A művelet meghívása előtt a Web API létrehozza a művelet hitelesítési szűrőinek listáját. Ide tartoznak a művelethatókörrel, a vezérlő hatókörével és a globális hatókörrel rendelkező szűrők.
- A Webes API meghívja a AuthenticateAsync-et a lista minden szűrőjén. Minden szűrő érvényesítheti a hitelesítő adatokat a kérelemben. Ha egy szűrő sikeresen ellenőrzi a hitelesítő adatokat, a szűrő létrehoz egy IPrincipal-t , és csatolja azt a kéréshez. A szűrő ezen a ponton hibát is kiválthat. Ha igen, a csővezeték többi része nem fut.
- Feltételezve, hogy nincs hiba, a kérés a folyamat többi részén halad át.
- Végül a Web API meghívja az összes hitelesítési szűrő ChallengeAsync metódusát. A szűrők ezt a módszert használják arra, hogy szükség esetén kihívást adjanak a válaszhoz. Általában (de nem mindig) ez 401-hiba esetén fordul elő.
Az alábbi ábrák két lehetséges esetet mutatnak be. Az elsőben a hitelesítési szűrő sikeresen hitelesíti a kérést, egy engedélyezési szűrő engedélyezi a kérést, a vezérlőművelet pedig 200 (OK) értéket ad vissza.
A második példában a hitelesítési szűrő hitelesíti a kérést, de az engedélyezési szűrő a 401-et (Jogosulatlan) adja vissza. Ebben az esetben a vezérlőművelet nem lesz meghívva. A hitelesítési szűrő hozzáad egy Www-Authenticate fejlécet a válaszhoz.
Más kombinációk is lehetségesek – például ha a vezérlőművelet névtelen kéréseket tesz lehetővé, lehet, hogy rendelkezik hitelesítési szűrővel, de nincs engedélye.
Az AuthenticateAsync metódus implementálása
A AuthenticateAsync metódus megpróbálja hitelesíteni a kérést. A metódus aláírása a következő:
Task AuthenticateAsync(
HttpAuthenticationContext context,
CancellationToken cancellationToken
)
Az AuthenticateAsync metódusnak az alábbiak egyikét kell elvégeznie:
- Semmi (Nincs művelet).
- Hozzon létre egy IPrincipal-t , és állítsa be a kérelemre.
- Állítson be hibás eredményt.
Az (1) lehetőség azt jelenti, hogy a kérés nem rendelkezik a szűrő által megértett hitelesítő adatokkal. A (2) lehetőség azt jelenti, hogy a szűrő sikeresen hitelesítette a kérést. A (3) lehetőség azt jelenti, hogy a kérelem hitelesítő adatai érvénytelenek (például helytelen jelszóval), ami hibaválaszt vált ki.
Az alábbiakban az AuthenticateAsync implementálásának általános vázlata található.
- Keresse meg a hitelesítő adatokat a kérelemben.
- Ha nincsenek hitelesítő adatok, ne tegyen semmit, és térjen vissza (no-op).
- Ha vannak hitelesítő adatok, de a szűrő nem ismeri fel a hitelesítési sémát, ne tegyen semmit, és adja vissza (no-op). A folyamat egy másik szűrője is megértheti a sémát.
- Ha vannak olyan hitelesítő adatok, amelyeket a szűrő megért, próbálja meg hitelesíteni őket.
- Ha a hitelesítő adatok helytelenek, a
context.ErrorResultbeállítással térítse vissza a 401-et. - Ha a hitelesítő adatok érvényesek, hozzon létre egy IPrincipal-t , és állítsa be
context.Principal.
Az alábbi kód az Alapszintű hitelesítési mintából származó AuthenticationAsync metódust mutatja be. A megjegyzések minden lépést jeleznek. A kód számos hibatípust jelenít meg: hitelesítő adatok nélküli engedélyezési fejlécet, hibásan formázott hitelesítő adatokat és rossz felhasználónevet/jelszót.
public async Task AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken)
{
// 1. Look for credentials in the request.
HttpRequestMessage request = context.Request;
AuthenticationHeaderValue authorization = request.Headers.Authorization;
// 2. If there are no credentials, do nothing.
if (authorization == null)
{
return;
}
// 3. If there are credentials but the filter does not recognize the
// authentication scheme, do nothing.
if (authorization.Scheme != "Basic")
{
return;
}
// 4. If there are credentials that the filter understands, try to validate them.
// 5. If the credentials are bad, set the error result.
if (String.IsNullOrEmpty(authorization.Parameter))
{
context.ErrorResult = new AuthenticationFailureResult("Missing credentials", request);
return;
}
Tuple<string, string> userNameAndPassword = ExtractUserNameAndPassword(authorization.Parameter);
if (userNameAndPassword == null)
{
context.ErrorResult = new AuthenticationFailureResult("Invalid credentials", request);
}
string userName = userNameAndPassword.Item1;
string password = userNameAndPassword.Item2;
IPrincipal principal = await AuthenticateAsync(userName, password, cancellationToken);
if (principal == null)
{
context.ErrorResult = new AuthenticationFailureResult("Invalid username or password", request);
}
// 6. If the credentials are valid, set principal.
else
{
context.Principal = principal;
}
}
Hibaeredmény beállítása
Ha a hitelesítő adatok érvénytelenek, a szűrőnek egy context.ErrorResult. Az IHttpActionResult szolgáltatásról további információt a Webes API 2 műveleteredményeiben talál.
Az alapszintű hitelesítési minta egy erre a célra alkalmas osztályt AuthenticationFailureResult tartalmaz.
public class AuthenticationFailureResult : IHttpActionResult
{
public AuthenticationFailureResult(string reasonPhrase, HttpRequestMessage request)
{
ReasonPhrase = reasonPhrase;
Request = request;
}
public string ReasonPhrase { get; private set; }
public HttpRequestMessage Request { get; private set; }
public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
return Task.FromResult(Execute());
}
private HttpResponseMessage Execute()
{
HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.Unauthorized);
response.RequestMessage = Request;
response.ReasonPhrase = ReasonPhrase;
return response;
}
}
A ChallengeAsync implementálása
A ChallengeAsync metódus célja, hogy szükség esetén hitelesítési kihívásokat adjon a válaszhoz. A metódus aláírása a következő:
Task ChallengeAsync(
HttpAuthenticationChallengeContext context,
CancellationToken cancellationToken
)
A rendszer meghívja a metódust a kérelemfolyamat minden hitelesítési szűrőjén.
Fontos tisztában lenni azzal, hogy a ChallengeAsync meghívása a HTTP-válasz létrehozása előtt , esetleg még a vezérlőművelet futtatása előtt történik. A ChallengeAsync meghívásakor context.Result tartalmaz egy IHttpActionResult parancsot, amelyet később használunk a HTTP-válasz létrehozásához. Így a ChallengeAsync meghívásakor még nem tud semmit a HTTP-válaszról. A ChallengeAsync metódusnak egy új context.Result az eredeti értéket. Ennek az IHttpActionResult-nak az eredetit context.Resultkell becsomagolnia.
Az eredeti IHttpActionResult a belső eredményt, az új IHttpActionResult pedig a külső eredményt. A külső eredménynek a következőket kell tennie:
- A HTTP-válasz létrehozásához hívja meg a belső eredményt.
- Vizsgálja meg a választ.
- Szükség esetén adjon hozzá hitelesítési kihívást a válaszhoz.
Az alábbi példa az alapszintű hitelesítés mintájából származik. Meghatároz egy IHttpActionResult-t a külső eredményhez.
public class AddChallengeOnUnauthorizedResult : IHttpActionResult
{
public AddChallengeOnUnauthorizedResult(AuthenticationHeaderValue challenge, IHttpActionResult innerResult)
{
Challenge = challenge;
InnerResult = innerResult;
}
public AuthenticationHeaderValue Challenge { get; private set; }
public IHttpActionResult InnerResult { get; private set; }
public async Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
HttpResponseMessage response = await InnerResult.ExecuteAsync(cancellationToken);
if (response.StatusCode == HttpStatusCode.Unauthorized)
{
// Only add one challenge per authentication scheme.
if (!response.Headers.WwwAuthenticate.Any((h) => h.Scheme == Challenge.Scheme))
{
response.Headers.WwwAuthenticate.Add(Challenge);
}
}
return response;
}
}
A InnerResult tulajdonság a belső IHttpActionResult tulajdonságot tartalmazza. A Challenge tulajdonság egy Www-Authentication fejlécet jelöl. Figyelje meg, hogy az ExecuteAsync először meghívja InnerResult.ExecuteAsync a HTTP-választ, majd szükség esetén hozzáadja a kihívást.
A feladat hozzáadása előtt ellenőrizze a válaszkódot. A legtöbb hitelesítési séma csak akkor ad kihívást, ha a válasz 401, ahogy az itt látható. Egyes hitelesítési sémák azonban kihívást jelentenek a sikeres válaszhoz. Lásd például az Egyeztetés (RFC 4559) című témakört.
Az osztály alapján AddChallengeOnUnauthorizedResult a ChallengeAsync tényleges kódja egyszerű. Hozza létre az eredményt, és csatolja a context.Result-hoz.
public Task ChallengeAsync(HttpAuthenticationChallengeContext context, CancellationToken cancellationToken)
{
var challenge = new AuthenticationHeaderValue("Basic");
context.Result = new AddChallengeOnUnauthorizedResult(challenge, context.Result);
return Task.FromResult(0);
}
Megjegyzés: Az alapszintű hitelesítési minta ezt a logikát kissé elvonatkoztatja, elhelyezve azt egy bővítménymetódusban.
Hitelesítési szűrők kombinálása Host-Level hitelesítéssel
A "gazdagépszintű hitelesítés" az a hitelesítés, amelyet a gazdagép (például az IIS) hajt végre, mielőtt a kérés eléri a webes API-keretrendszert.
Előfordulhat, hogy az alkalmazás többi részében engedélyezni szeretné a gazdagépszintű hitelesítést, de letilthatja a webes API-vezérlők esetében. Például egy tipikus forgatókönyv az, hogy a Forms Authentication-t a gazda szintjén engedélyezzük, míg a Web API esetében jogkivonat-alapú hitelesítést használunk.
Ha le szeretné tiltani a gazdagépszintű hitelesítést a webes API pipeline-ban, hívja meg config.SuppressHostPrincipal() a konfigurációban. Ez azt eredményezi, hogy a Webes API eltávolítja az IPrincipal-t a webes API-folyamatba belépő kérésekből. Gyakorlatilag "nem hitelesíti" a kérést.
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.SuppressHostPrincipal();
// Other configuration code not shown...
}
}
További források
ASP.NET Webes API biztonsági szűrői (MSDN Magazin)