Geschützte Web-API: Überprüfen von Bereichen und App-Rollen

Dieser Artikel beschreibt, wie Sie Ihrer Web-API eine Berechtigung hinzufügen können. Dieser Schutz stellt sicher, dass die API nur aufgerufen wird von:

  • Anwendungen im Auftrag von Benutzern, die über die richtigen Bereiche und Rollen verfügen
  • Daemon-Apps mit den richtigen Anwendungsrollen

Die Codeausschnitte in diesem Artikel stammen aus den folgenden Codebeispielen auf GitHub:

Um eine ASP.NET- oder ASP.NET Core-Web-API zu schützen, müssen Sie das [Authorize]-Attribut einem der folgenden Elemente hinzufügen:

  • dem Controller selbst, wenn alle Aktionen des Controllers geschützt werden sollen
  • einer individuellen Controlleraktion für Ihre API
    [Authorize]
    public class TodoListController : Controller
    {
     // ...
    }

Aber dieser Schutz reicht nicht aus. Es wird nur garantiert, dass ASP.NET und ASP.NET Core das Token validieren. Ihre API muss überprüfen, ob das zum Aufrufen der API verwendete Token mit den erwarteten Ansprüchen angefordert wurde. Diese Ansprüche müssen insbesondere überprüft werden:

  • Die Bereiche, wenn die API im Namen eines Benutzers aufgerufen wird.
  • Die App-Rollen, wenn die API von einer Daemon-App aufgerufen wird.

Überprüfen von Bereichen in APIs, die im Namen von Benutzern aufgerufen werden

Wenn Ihre API von einer Client-App im Namen eines Benutzers aufgerufen wird, muss sie ein Bearertoken anfordern, das bestimmte Bereiche für die API enthält. Weitere Informationen finden Sie unter Codekonfiguration | Bearertoken.

In ASP.NET Core können Sie Microsoft.Identity.Web verwenden, um Bereiche in jeder Controlleraktion zu überprüfen. Sie können sie auch auf der Controllerebene oder für die gesamte Anwendung überprüfen.

Überprüfen der Bereiche bei jeder Controlleraktion

Sie können die Bereiche in der Controlleraktion mithilfe des [RequiredScope]-Attributs überprüfen. Dieses Attribut weist mehrere Außerkraftsetzungen auf. Eine, die die erforderlichen Bereiche direkt übernimmt, und eine, die einen Schlüssel für die Konfiguration übernimmt.

Überprüfen der Bereiche für eine Controlleraktion mit hartcodierten Bereichen

Der folgende Codeausschnitt zeigt die Verwendung des [RequiredScope]-Attributs mit hartcodierten Bereichen.

using Microsoft.Identity.Web

[Authorize]
public class TodoListController : Controller
{
    /// <summary>
    /// The web API will accept only tokens that have the `access_as_user` scope for
    /// this API.
    /// </summary>
    const string scopeRequiredByApi = "access_as_user";

    // GET: api/values
    [HttpGet]
    [RequiredScope(scopeRequiredByApi)]
    public IEnumerable<TodoItem> Get()
    {
        // Do the work and return the result.
        // ...
    }
 // ...
}
Überprüfen der Bereiche für eine Controlleraktion mit in der Konfiguration definierten Bereichen

Sie können diese erforderlichen Bereiche auch in der Konfiguration deklarieren und auf den Konfigurationsschlüssel verweisen:

Beispiel: In appsettings.json haben Sie die folgende Konfiguration:

{
 "AzureAd" : {
   // more settings
   "Scopes" : "access_as_user access_as_admin"
  }
}

Verweisen Sie dann im [RequiredScope]-Attribut darauf:

using Microsoft.Identity.Web

[Authorize]
public class TodoListController : Controller
{
    // GET: api/values
    [HttpGet]
    [RequiredScope(RequiredScopesConfigurationKey = "AzureAd:Scopes")]
    public IEnumerable<TodoItem> Get()
    {
        // Do the work and return the result.
        // ...
    }
 // ...
}
Bedingtes Überprüfen von Bereichen

Es gibt Fälle, in denen Sie Bereiche bedingt überprüfen möchten. Hierzu können Sie die VerifyUserHasAnyAcceptedScope-Erweiterungsmethode für HttpContext verwenden.

using Microsoft.Identity.Web

[Authorize]
public class TodoListController : Controller
{
    /// <summary>
    /// The web API will accept only tokens 1) for users, 2) that have the `access_as_user` scope for
    /// this API.
    /// </summary>
    static readonly string[] scopeRequiredByApi = new string[] { "access_as_user" };

    // GET: api/values
    [HttpGet]
    public IEnumerable<TodoItem> Get()
    {
         HttpContext.VerifyUserHasAnyAcceptedScope(scopeRequiredByApi);
        // Do the work and return the result.
        // ...
    }
 // ...
}

Überprüfen der Bereiche auf Controllerebene

Sie können die Bereiche auch auf Controllerebene überprüfen.

Überprüfen der Bereiche für einen Controller mit hartcodierten Bereichen

Der folgende Codeausschnitt zeigt die Verwendung des [RequiredScope]-Attributs mit hartcodierten Bereichen auf dem Controller. Um das „RequiredScopeAttribute“ zu verwenden, müssen Sie einen der folgenden Schritte durchführen:

  • Verwenden Sie AddMicrosoftIdentityWebApi in der Datei Startup.cs, wie unter Codekonfiguration veranschaulicht.
  • Oder fügen Sie auf andere Weise ScopeAuthorizationRequirement zu den Richtlinien für die Autorisierung hinzu, wie in Autorisierungsrichtlinien erläutert.
using Microsoft.Identity.Web

[Authorize]
[RequiredScope(scopeRequiredByApi)]
public class TodoListController : Controller
{
    /// <summary>
    /// The web API will accept only tokens 1) for users, 2) that have the `access_as_user` scope for
    /// this API.
    /// </summary>
    static readonly string[] scopeRequiredByApi = new string[] { "access_as_user" };

    // GET: api/values
    [HttpGet]
    public IEnumerable<TodoItem> Get()
    {
        // Do the work and return the result.
        // ...
    }
 // ...
}
Überprüfen der Bereiche für einen Controller mit in der Konfiguration definierten Bereichen

Wie bei Aktionen können Sie diese erforderlichen Bereiche auch in der Konfiguration deklarieren und auf den Konfigurationsschlüssel verweisen:

using Microsoft.Identity.Web

[Authorize]
[RequiredScope(RequiredScopesConfigurationKey = "AzureAd:Scopes")]
public class TodoListController : Controller
{
    // GET: api/values
    [HttpGet]
    public IEnumerable<TodoItem> Get()
    {
        // Do the work and return the result.
        // ...
    }
 // ...
}

Globaleres Überprüfen der Bereiche

Als Vorgehensweise werden die Definition präziser Bereiche für Ihre Web-API und die Überprüfung der Bereiche bei jeder Controlleraktion empfohlen. Es ist jedoch auch möglich, die Bereiche auf Anwendungs- oder Controllerebene zu überprüfen. Einzelheiten hierzu finden Sie in der ASP.NET Core-Dokumentation unter Anspruchsbasierte Autorisierung.

Was wird überprüft?

Mit dem [RequiredScope]-Attribut und der VerifyUserHasAnyAcceptedScope-Methode werden in etwa folgende Schritte ausgeführt:

  • Überprüfen, ob ein Anspruch mit dem Namen http://schemas.microsoft.com/identity/claims/scope oder scp vorhanden ist
  • Überprüfen, ob der Anspruch einen Wert hat, der den von der API erwarteten Bereich enthält

Überprüfen von App-Rollen in APIs, die von Daemon-Apps aufgerufen werden

Wenn Ihre Web-API von einer Daemon-App aufgerufen wird, sollte diese App eine Anwendungsberechtigung für Ihre Web-API anfordern. Unter Verfügbarmachen von Anwendungsberechtigungen (App-Rollen) haben Sie gesehen, dass Ihre API solche Berechtigungen verfügbar macht. Ein Beispiel hierfür ist die App-Rolle access_as_application.

Ihre API muss nun überprüfen, ob das empfangene Token den Anspruch roles enthält und ob dieser Anspruch den erwarteten Wert hat. Der Prüfcode ähnelt dem Code, der delegierte Berechtigungen überprüft, wobei jedoch Ihre Controlleraktion jetzt Rollen und nicht Bereiche testet:

Der folgende Codeausschnitt zeigt, wie Sie die Anwendungsrolle überprüfen.

using Microsoft.Identity.Web

[Authorize]
public class TodoListController : ApiController
{
    public IEnumerable<TodoItem> Get()
    {
        HttpContext.ValidateAppRole("access_as_application");
        // ...
    }

Stattdessen können Sie die Attribute [Authorize(Roles = "access_as_application")] auf dem Controller oder einer Aktion (oder einer Razor Page) verwenden.

[Authorize(Roles = "access_as_application")]
MyController : ApiController
{
    // ...
}

Unter rollenbasierte Autorisierung in ASP.NET Core sind verschiedene Ansätze zum Implementieren der rollenbasierten Autorisierung aufgeführt. Entwickler können einen Ansatz auswählen, der für ihr jeweiliges Szenario geeignet ist.

Funktionstüchtige Beispiele finden Sie im inkrementellen Web-App-Tutorial zur Autorisierung nach Rollen und Gruppen.

Überprüfen von App-Rollen in APIs, die im Namen von Benutzern aufgerufen werden

Benutzer können auch Rollenansprüche in Benutzerzuweisungsmustern verwenden, wie unter Hinzufügen von App-Rollen in Ihrer Anwendung und Empfangen der Rollen im Token beschrieben. Wenn Sie also Rollen überprüfen, können sich Apps als Benutzer anmelden und umgekehrt, wenn die Rollen beiden zugewiesen werden können. Wir empfehlen, verschiedene Rollen für Benutzer und Apps zu deklarieren, um diese Verwechslung zu vermeiden.

Wenn Sie App-Rollen mit Benutzer/Gruppe definiert haben, kann der Rollenanspruch auch in der API zusammen mit den Bereichen überprüft werden. Die Überprüfungslogik der App-Rollen in diesem Szenario bleibt unverändert, als ob die API von den Daemon-Apps aufgerufen würde, da es keine Unterscheidung im Rollenanspruch für Benutzer/Gruppe und Anwendung gibt.

Akzeptieren von reinen App-Token, wenn die Web-API nur von Daemon-Apps aufgerufen werden sollte

Wenn nur Daemon-Apps Ihre Web-API aufrufen können sollen, fügen Sie bei der Validierung der App-Rolle die Bedingung hinzu, dass das Token ein reines App-Token sein muss.

string oid = ClaimsPrincipal.Current.FindFirst("oid")?.Value;
string sub = ClaimsPrincipal.Current.FindFirst("sub")?.Value;
bool isAppOnly = oid != null && sub != null && oid == sub;

Durch das Überprüfen der inversen Bedingung können nur Apps, die einen Benutzer anmelden, Ihre API aufrufen.

Verwenden der ACL-basierten Autorisierung

Alternativ zur auf Anwendungsrollen basierenden Autorisierung können Sie Ihre Web-API mit einem ACL-basierten Autorisierungsmuster (Zugriffssteuerungsliste) schützen, um Token ohne den roles-Anspruch zu steuern.

Wenn Sie Microsoft.Identity.Web auf ASP.NET Core verwenden, müssen Sie deklarieren, dass Sie die ACL-basierte Autorisierung verwenden. Andernfalls löst Microsoft Identity Web eine Ausnahme aus, wenn sich weder Rollen noch Bereiche in den bereitgestellten Ansprüchen befinden:

System.UnauthorizedAccessException: IDW10201: Neither scope or roles claim was found in the bearer token.

Um diese Ausnahme zu vermeiden, legen Sie die Konfigurationseigenschaft AllowWebApiToBeAuthorizedByACL in appsettings.json oder programmgesteuert auf true fest.

{
 "AzureAD"
 {
  // other properties
  "AllowWebApiToBeAuthorizedByACL" : true,
  // other properties
 }
}

Wenn Sie AllowWebApiToBeAuthorizedByACL auf true festlegen, liegt es in Ihrer Verantwortung, den ACL-Mechanismus sicherzustellen.

Nächste Schritte

  • Erfahren Sie mehr, indem Sie in der folgenden mehrteiligen Tutorial-Serie eine ASP.NET Core Web-App für die Benutzeranmeldung erstellen.

  • Erkunden von Beispielen für Web-APIs der Microsoft Identitätsplattform