Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
von Rick Anderson
Sie haben eine Web-API erstellt, aber jetzt möchten Sie den Zugriff darauf steuern. In dieser Artikelreihe befassen wir uns mit einigen Optionen zum Sichern einer Web-API vor nicht autorisierten Benutzern. Diese Reihe deckt sowohl die Authentifizierung als auch die Autorisierung ab.
- Die Authentifizierung kennt die Identität des Benutzers. Alice meldet sich beispielsweise mit ihrem Benutzernamen und Kennwort an, und der Server verwendet das Kennwort, um Alice zu authentifizieren.
- Die Autorisierung entscheidet, ob ein Benutzer eine Aktion ausführen darf. Beispielsweise verfügt Alice über die Berechtigung zum Abrufen einer Ressource, aber nicht zum Erstellen einer Ressource.
Der erste Artikel in der Reihe bietet eine allgemeine Übersicht über die Authentifizierung und Autorisierung in ASP.NET Web-API. Weitere Themen beschreiben allgemeine Authentifizierungsszenarien für die Web-API.
Hinweis
Dank der Leute, die diese Serie bewertet und wertvolles Feedback gegeben haben: Rick Anderson, Levi Broderick, Barry Dorrans, Tom Dykstra, Hongmei Ge, David Matson, Daniel Roth, Tim Teebken.
Authentifizierung
Web-API geht davon aus, dass die Authentifizierung im Host erfolgt. Für webhosting ist der Host IIS, der HTTP-Module für die Authentifizierung verwendet. Sie können Ihr Projekt so konfigurieren, dass eines der in IIS oder ASP.NET integrierten Authentifizierungsmodule verwendet wird, oder Ihr eigenes HTTP-Modul zum Ausführen einer benutzerdefinierten Authentifizierung schreiben.
Wenn der Host den Benutzer authentifiziert, wird ein Prinzipal erstellt, bei dem es sich um ein IPrincipal-Objekt handelt, das den Sicherheitskontext darstellt, unter dem Code ausgeführt wird. Der Host ordnet den Prinzipal dem aktuellen Thread zu, indem er Thread.CurrentPrincipal festlegt. Der Hauptbenutzer enthält ein zugeordnetes Identity-Objekt, das Informationen zum Benutzer enthält. Wenn der Benutzer authentifiziert ist, gibt die Identity.IsAuthenticated-Eigenschaft"true" zurück. Bei anonymen Anforderungen gibt IsAuthenticated"false" zurück. Weitere Informationen zu Prinzipien finden Sie unter Rollenbasierte Sicherheit.
HTTP-Nachrichtenhandler für die Authentifizierung
Anstatt den Host für die Authentifizierung zu verwenden, können Sie die Authentifizierungslogik in einen HTTP-Nachrichtenhandler einfügen. In diesem Fall überprüft der Nachrichten-Handler die HTTP-Anfrage und setzt den Principal fest.
Wann sollten Sie Nachrichtenhandler für die Authentifizierung verwenden? Hier sind einige Kompromisse:
- Ein HTTP-Modul sieht alle Anforderungen, die die ASP.NET Pipeline durchlaufen. Ein Nachrichtenhandler sieht nur Anforderungen, die an die Web-API weitergeleitet werden.
- Sie können Nachrichtenhandler pro Route festlegen, mit denen Sie ein Authentifizierungsschema auf eine bestimmte Route anwenden können.
- HTTP-Module sind spezifisch für IIS. Nachrichtenhandler sind host-agnostisch und können sowohl mit Webhosting als auch mit Eigenhosting verwendet werden.
- HTTP-Module nehmen an der IIS-Protokollierung, -Überwachung usw. teil.
- HTTP-Module werden weiter oben in der Pipeline ausgeführt. Wenn Sie die Authentifizierung in einem Nachricht-Handler behandeln, wird der Hauptbenutzer erst festgelegt, wenn der Handler ausgeführt wird. Darüber hinaus wird der Principal wieder auf den vorherigen Principal zurückgesetzt, sobald die Antwort den Nachrichten-Handler verlässt.
Im Allgemeinen ist ein HTTP-Modul eine bessere Option, wenn Sie das Self-Hosting nicht unterstützen müssen. Wenn Sie Self-Hosting unterstützen müssen, sollten Sie einen Nachrichtenhandler in Betracht ziehen.
Festlegen des Prinzipals
Wenn Ihre Anwendung eine benutzerdefinierte Authentifizierungslogik ausführt, müssen Sie den Principal an zwei Stellen festlegen:
- Thread.CurrentPrincipal. Diese Eigenschaft ist der Standardweg zum Festlegen des Thread-Principals in .NET.
- HttpContext.Current.User. Diese Eigenschaft ist spezifisch für ASP.NET.
Der folgende Code zeigt, wie der Principal gesetzt wird.
private void SetPrincipal(IPrincipal principal)
{
Thread.CurrentPrincipal = principal;
if (HttpContext.Current != null)
{
HttpContext.Current.User = principal;
}
}
Für Webhosting müssen Sie den Prinzipal an beiden Stellen festlegen; andernfalls kann der Sicherheitskontext inkonsistent werden. Bei Self-Hosting ist httpContext.Current jedoch null. Um sicherzustellen, dass Ihr Code host-agnostisch ist, überprüfen Sie daher auf NULL, wie dargestellt, bevor Sie HttpContext.Current zuweisen.
Autorisierung
Die Autorisierung erfolgt später in der Pipeline, näher am Controller. Auf diese Weise können Sie präzisere Entscheidungen treffen, wenn Sie Zugriff auf Ressourcen gewähren.
- Autorisierungsfilter werden vor der Controlleraktion ausgeführt. Wenn die Anforderung nicht autorisiert ist, gibt der Filter eine Fehlerantwort zurück, und die Aktion wird nicht aufgerufen.
- Innerhalb einer Controlleraktion können Sie die aktuelle Identität aus der Eigenschaft ApiController.User abrufen. Sie können z. B. eine Liste von Ressourcen basierend auf dem Benutzernamen filtern und nur die Ressourcen zurückgeben, die zu diesem Benutzer gehören.
Verwenden des [Authorize]-Attributs
Die Web-API stellt einen integrierten Autorisierungsfilter ,AuthorizeAttribute" bereit. Dieser Filter überprüft, ob der Benutzer authentifiziert ist. Ist dies nicht der Fehler, wird der HTTP-Statuscode 401 (Nicht autorisiert) zurückgegeben, ohne die Aktion aufrufen zu müssen.
Sie können den Filter global, auf Controllerebene oder auf ebene einzelner Aktionen anwenden.
Global: Um den Zugriff für jeden Web-API-Controller einzuschränken, fügen Sie der globalen Filterliste den AuthorizeAttribute-Filter hinzu:
public static void Register(HttpConfiguration config)
{
config.Filters.Add(new AuthorizeAttribute());
}
Controller: Um den Zugriff für einen bestimmten Controller einzuschränken, fügen Sie den Filter als Attribut zum Controller hinzu:
// Require authorization for all actions on the controller.
[Authorize]
public class ValuesController : ApiController
{
public HttpResponseMessage Get(int id) { ... }
public HttpResponseMessage Post() { ... }
}
Aktion: Um den Zugriff auf bestimmte Aktionen einzuschränken, fügen Sie das Attribut zur Aktionsmethode hinzu:
public class ValuesController : ApiController
{
public HttpResponseMessage Get() { ... }
// Require authorization for a specific action.
[Authorize]
public HttpResponseMessage Post() { ... }
}
Alternativ können Sie den Controller einschränken und dann den anonymen Zugriff auf bestimmte Aktionen mithilfe des [AllowAnonymous] Attributs zulassen. Im folgenden Beispiel ist die Post Methode eingeschränkt, aber die Get Methode ermöglicht anonymen Zugriff.
[Authorize]
public class ValuesController : ApiController
{
[AllowAnonymous]
public HttpResponseMessage Get() { ... }
public HttpResponseMessage Post() { ... }
}
In den vorherigen Beispielen ermöglicht der Filter allen authentifizierten Benutzern den Zugriff auf die eingeschränkten Methoden; nur anonyme Benutzer werden ausgesperrt. Sie können den Zugriff auch auf bestimmte Benutzer oder auf Benutzer in bestimmten Rollen einschränken.
// Restrict by user:
[Authorize(Users="Alice,Bob")]
public class ValuesController : ApiController
{
}
// Restrict by role:
[Authorize(Roles="Administrators")]
public class ValuesController : ApiController
{
}
Hinweis
Der AuthorizeAttribute-Filter für Web-API-Controller befindet sich im System.Web.Http-Namespace . Es gibt einen ähnlichen Filter für MVC-Controller im System.Web.Mvc-Namespace , der nicht mit Web-API-Controllern kompatibel ist.
Benutzerdefinierte Autorisierungsfilter
Um einen benutzerdefinierten Autorisierungsfilter zu schreiben, leiten Sie einen der folgenden Typen ab:
- AuthorizeAttribute. Erweitern Sie diese Klasse, um Autorisierungslogik basierend auf dem aktuellen Benutzer und den Rollen des Benutzers auszuführen.
- AuthorizationFilterAttribute. Erweitern Sie diese Klasse, um synchrone Autorisierungslogik auszuführen, die nicht unbedingt auf dem aktuellen Benutzer oder der aktuellen Rolle basiert.
- IAuthorizationFilter. Implementieren Sie diese Schnittstelle, um asynchrone Autorisierungslogik auszuführen; Wenn Ihre Autorisierungslogik beispielsweise asynchrone E/A- oder Netzwerkaufrufe vorsetzt. (Wenn Ihre Autorisierungslogik CPU-gebunden ist, ist es einfacher, von AuthorizationFilterAttribute abzuleiten, da Sie keine asynchrone Methode schreiben müssen.)
Das folgende Diagramm zeigt die Klassenhierarchie für die AuthorizeAttribute-Klasse .
Diagramm der Klassenhierarchie für die Authorize-Attributklasse. Das "Authorize"-Attribut befindet sich unten, mit einem Pfeil, der auf das Autorisierungsfilter-Attribut zeigt, und ein Pfeil, der oben auf den "I Authorization Filter" zeigt.
Autorisierung innerhalb einer Controlleraktion
In einigen Fällen könnten Sie erlauben, dass eine Anfrage fortgesetzt wird, aber das Verhalten basierend auf dem Hauptverantwortlichen ändern. Beispielsweise können sich die zurückgegebenen Informationen je nach Rolle des Benutzers ändern. Innerhalb einer Controllermethode können Sie den aktuellen Benutzerprinzipal über die ApiController.User-Eigenschaft abrufen.
public HttpResponseMessage Get()
{
if (User.IsInRole("Administrators"))
{
// ...
}
}