Freigeben über


Lernprogramm: Erstellen und Sichern einer ASP.NET Core-Web-API mit der Microsoft Identity Platform

Gilt für:Grüner Kreis mit weißem Häkchen. Mitarbeitermandanten Grüner Kreis mit weißem Häkchen. Externe Mandanten (weitere Informationen)

In dieser Lernprogrammreihe wird veranschaulicht, wie Sie eine ASP.NET Core-Web-API mit der Microsoft Identity Platform schützen, um den Zugriff auf autorisierte Benutzer und Client-Apps zu beschränken. Die web-API, die Sie erstellen, verwendet sowohl delegierte Berechtigungen (Bereiche) als auch Anwendungsberechtigungen (App-Rollen).

In diesem Tutorial führen Sie Folgendes durch:

  • Erstellen einer ASP.NET Core-Web-API
  • Konfigurieren der Web-API für die Verwendung der Registrierungsdetails der Microsoft Entra-App
  • Schützen Ihrer Web-API-Endpunkte
  • Führen Sie die Web-API aus, um sicherzustellen, dass sie HTTP-Anforderungen überwacht

Voraussetzungen

Erstellen eines neuen ASP.NET Core-Web-API-Projekts

Führen Sie die folgenden Schritte aus, um ein minimales ASP.NET Core-Web-API-Projekt zu erstellen:

  1. Öffnen Sie Ihr Terminal in Visual Studio Code oder einem anderen Code-Editor, und navigieren Sie zu dem Verzeichnis, in dem Sie Ihr Projekt erstellen möchten.

  2. Führen Sie die folgenden Befehle auf der .NET CLI oder einem anderen Befehlszeilentool aus.

    dotnet new web -o TodoListApi
    cd TodoListApi
    
  3. Wählen Sie "Ja " aus, wenn ein Dialogfeld fragt, ob Sie den Autoren vertrauen möchten.

  4. Wählen Sie "Ja " aus, wenn ein Dialogfeld fragt, ob Sie dem Projekt erforderliche Ressourcen hinzufügen möchten.

Installieren Sie die erforderlichen Pakete

Um die ASP.NET Core-Web-API zu erstellen, zu schützen und zu testen, müssen Sie die folgenden Pakete installieren:

  • Microsoft.EntityFrameworkCore.InMemory– Ein Paket, mit dem Sie Entity Framework Core mit einer In-Memory-Datenbank verwenden können. Es ist nützlich für Testzwecke, ist aber nicht für den Produktionseinsatz konzipiert.
  • Microsoft.Identity.Web – eine Reihe von ASP.NET Core-Bibliotheken, die das Hinzufügen von Authentifizierungs- und Autorisierungsunterstützung zu Web-Apps und Web-APIs vereinfachen, die in die Microsoft Identity Platform integriert werden.

Verwenden Sie folgendes, um das Paket zu installieren:

dotnet add package Microsoft.EntityFrameworkCore.InMemory
dotnet add package Microsoft.Identity.Web

Konfigurieren von Anwendungsregistrierungsdetails

Öffnen Sie die dateiappsettings.json in Ihrem App-Ordner, und fügen Sie die App-Registrierungsdetails hinzu, die Sie nach der Registrierung der Web-API aufgezeichnet haben.

{
    "AzureAd": {
        "Instance": "Enter_the_Authority_URL_Here",
        "TenantId": "Enter_the_Tenant_Id_Here",
        "ClientId": "Enter_the_Application_Id_Here"
    },
    "Logging": {...},
  "AllowedHosts": "*"
}

Ersetzen Sie die folgenden Platzhalter wie gezeigt:

  • Ersetzen Sie Enter_the_Application_Id_Here durch Ihre Anwendungs-ID (Client-ID).
  • Ersetzen Sie Enter_the_Tenant_Id_Here durch Ihre Verzeichnis-ID (Mandanten-ID).
  • Ersetzen Sie Enter_the_Authority_URL_Here durch Ihre Autoritäts-URL, wie im nächsten Abschnitt erläutert.

Autoritäts-URL für Ihre App

Die Autoritäts-URL gibt das Verzeichnis an, aus dem die Microsoft-Authentifizierungsbibliothek (MSAL) Token anfordern kann. Sie entwickeln es sowohl für das Personal als auch für externe Mieter auf unterschiedliche Weise, wie gezeigt:

//Instance for workforce tenant
Instance: "https://login.microsoftonline.com/"

Verwenden einer benutzerdefinierten URL-Domäne (optional)

Benutzerdefinierte URL-Domänen werden in Mitarbeitermandanten nicht unterstützt.

Berechtigungen hinzufügen

Alle APIs müssen mindestens einen Bereich (auch „delegierte Berechtigung“ genannt) veröffentlichen, damit die Clientanwendungen erfolgreich ein Zugriffstoken für Benutzer*innen abrufen können. APIs sollten auch mindestens eine App-Rolle veröffentlichen, die auch als Anwendungsberechtigungen bezeichnet wird, damit die Client-Apps ein Zugriffstoken im eigenen Namen abrufen, also dann, wenn sie keinen Benutzer anmelden.

Wir geben diese Berechtigungen in der Datei appsettings.json an. In diesem Tutorial haben Sie die folgenden delegierten und Anwendungsberechtigungen registriert:

  • Delegierte Berechtigungen:ToDoList.Read und ToDoList.ReadWrite.
  • Anwendungsberechtigungen:ToDoList.Read.All und ToDoList.ReadWrite.All.

Wenn ein Benutzer oder eine Clientanwendung die Web-API aufruft, werden nur Clients mit diesen Bereichen oder Berechtigungen für den Zugriff auf den geschützten Endpunkt autorisiert.

{
  "AzureAd": {
    "Instance": "Enter_the_Authority_URL_Here",
    "TenantId": "Enter_the_Tenant_Id_Here",
    "ClientId": "Enter_the_Application_Id_Here",
    "Scopes": {
      "Read": ["ToDoList.Read", "ToDoList.ReadWrite"],
      "Write": ["ToDoList.ReadWrite"]
    },
    "AppPermissions": {
      "Read": ["ToDoList.Read.All", "ToDoList.ReadWrite.All"],
      "Write": ["ToDoList.ReadWrite.All"]
    }
  },
  "Logging": {...},
  "AllowedHosts": "*"
}

Implementieren von Authentifizierung und Autorisierung in der API

Um die Authentifizierung und Autorisierung zu konfigurieren, öffnen Sie die program.cs Datei, und ersetzen Sie deren Inhalt durch die folgenden Codeausschnitte:

Hinzufügen eines Authentifizierungsschemas

In dieser API verwenden wir das JSON Web Token (JWT)-Bearerschema als Standardauthentifizierungsmechanismus. Verwenden Sie die AddAuthentication Methode, um das JWT-Bearerschema zu registrieren.

// Add required packages to your imports
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Identity.Web;

var builder = WebApplication.CreateBuilder(args);

// Add an authentication scheme
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApi(builder.Configuration);

Erstellen des App-Modells

Erstellen Sie im Stammordner des Projekts einen Ordner namens "Models". Navigieren Sie zum Ordner "Models ", und erstellen Sie eine Datei mit dem Namen ToDo.cs , und fügen Sie dann den folgenden Code hinzu.

using System;

namespace ToDoListAPI.Models;

public class ToDo
{
    public int Id { get; set; }
    public Guid Owner { get; set; }
    public string Description { get; set; } = string.Empty;
}

Der vorangehende Code erstellt ein Modell namens ToDo. Dieses Modell stellt Daten dar, die die App verwaltet.

Hinzufügen eines Datenbankkontexts

Als Nächstes definieren wir eine Datenbankkontextklasse, die die Entity Framework-Funktionalität für ein Datenmodell koordiniert. Diese Klasse erbt von der Microsoft.EntityFrameworkCore.DbContext-Klasse , die Interaktionen zwischen der Anwendung und der Datenbank verwaltet. Führen Sie die folgenden Schritte aus, um den Datenbankkontext hinzuzufügen:

  1. Erstellen Sie einen Ordner namens "DbContext" im Stammordner Ihres Projekts.

  2. Navigieren Sie in den DbContext-Ordner , und erstellen Sie eine Datei mit dem Namen ToDoContext.cs , und fügen Sie dann den folgenden Code hinzu:

    using Microsoft.EntityFrameworkCore;
    using ToDoListAPI.Models;
    
    namespace ToDoListAPI.Context;
    
    public class ToDoContext : DbContext
    {
        public ToDoContext(DbContextOptions<ToDoContext> options) : base(options)
        {
        }
    
        public DbSet<ToDo> ToDos { get; set; }
    }
    
  3. Öffnen Sie die Program.cs Datei im Stammordner Ihres Projekts, und aktualisieren Sie sie mit dem folgenden Code:

    // Add the following to your imports
    using ToDoListAPI.Context;
    using Microsoft.EntityFrameworkCore;
    
    //Register ToDoContext as a service in the application
    builder.Services.AddDbContext<ToDoContext>(opt =>
        opt.UseInMemoryDatabase("ToDos"));
    

Im vorherigen Codeausschnitt registrieren wir DB-Kontext als bereichsbezogenen Dienst im ASP.NET Core-Anwendungsdienstanbieter (auch bekannt als Abhängigkeitseinfügungscontainer). Außerdem konfigurieren Sie die ToDoContext Klasse für die Verwendung einer In-Memory-Datenbank für die ToDo-Listen-API.

Einrichten eines Controllers

Controller implementieren in der Regel CruD-Aktionen (Create, Read, Update, Delete) zum Verwalten von Ressourcen. Da sich dieses Lernprogramm stärker auf den Schutz der API-Endpunkte konzentriert, implementieren wir nur zwei Aktionselemente im Controller. Eine "Alle lesen"-Aktion, um alle To-Do-Elemente abzurufen, und eine Erstellen-Aktion, um ein neues To-Do-Element hinzuzufügen. Führen Sie die folgenden Schritte aus, um Ihrem Projekt einen Controller hinzuzufügen:

  1. Navigieren Sie zum Stammordner Ihres Projekts, und erstellen Sie einen Ordner mit dem Namen "Controller".

  2. Erstellen Sie eine Datei ToDoListController.cs namens im Ordner "Controller ", und fügen Sie den folgenden Code für die Kesselplatte hinzu:

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Identity.Web;
using Microsoft.Identity.Web.Resource;
using ToDoListAPI.Models;
using ToDoListAPI.Context;

namespace ToDoListAPI.Controllers;

[Authorize]
[Route("api/[controller]")]
[ApiController]
public class ToDoListController : ControllerBase
{
    private readonly ToDoContext _toDoContext;

    public ToDoListController(ToDoContext toDoContext)
    {
        _toDoContext = toDoContext;
    }

    [HttpGet()]
    [RequiredScopeOrAppPermission()]
    public async Task<IActionResult> GetAsync(){...}

    [HttpPost]
    [RequiredScopeOrAppPermission()]
    public async Task<IActionResult> PostAsync([FromBody] ToDo toDo){...}

    private bool RequestCanAccessToDo(Guid userId){...}

    private Guid GetUserId(){...}

    private bool IsAppMakingRequest(){...}
}

Hinzufügen von Code zum Controller

In diesem Abschnitt wird erläutert, wie Sie code zum Controllergerüst hinzufügen, das im vorherigen Abschnitt erstellt wurde. Der Fokus liegt hier auf dem Schutz der API, nicht auf der Erstellung.

  1. Importieren Sie die erforderlichen Pakete: Das Microsoft.Identity.Web Paket ist ein Wrapper um MSAL.NET, mit dem wir die Authentifizierungslogik wie die Verarbeitung der Tokenüberprüfung problemlos verarbeiten können. Um sicherzustellen, dass unsere Endpunkte eine Autorisierung erfordern, verwenden wir das integrierte Microsoft.AspNetCore.Authorization Paket.

  2. Da wir die Berechtigungen für den Aufruf dieser API entweder mithilfe von delegierten Berechtigungen im Namen des Benutzers oder mithilfe von Anwendungsberechtigungen erteilt haben, bei denen der Aufruf durch den Client selbst und nicht im Namen des Benutzers erfolgt, ist es wichtig zu wissen, ob der Aufruf von der App in ihrem eigenen Namen erfolgt. Am einfachsten finden Sie, ob das Zugriffstoken den idtyp optionalen Anspruch enthält. Der Anspruch idtyp ist der einfachste Weg, wie die API feststellen kann, ob ein Token ein App-Token oder ein App- und Benutzertoken ist. Es wird empfohlen, den optionalen Anspruch idtyp zu aktivieren.

    Wenn der Anspruch idtyp nicht aktiviert ist, können Sie die Ansprüche roles und scp verwenden, um zu bestimmen, ob es sich bei dem Zugriffstoken um ein App-Token oder um ein App- und Benutzertoken handelt. Ein von der Microsoft Entra-ID ausgestelltes Zugriffstoken verfügt über mindestens einen der beiden Ansprüche. Für Benutzende ausgestellte Zugriffstoken verfügen über den Anspruch scp. Für eine Anwendung ausgestellte Zugriffstoken verfügen über den Anspruch roles. Zugriffstoken, die beide Ansprüche enthalten, werden nur für Benutzer*innen ausgestellt, wobei der Anspruch scp die delegierten Berechtigungen festlegt, während der Anspruch roles die Rolle des Benutzers oder der Benutzerin festlegt. Zugriffstoken, die keinen der beiden Ansprüche enthalten, sind nicht zu berücksichtigen.

    private bool IsAppMakingRequest()
    {
        if (HttpContext.User.Claims.Any(c => c.Type == "idtyp"))
        {
            return HttpContext.User.Claims.Any(c => c.Type == "idtyp" && c.Value == "app");
        }
        else
        {
            return HttpContext.User.Claims.Any(c => c.Type == "roles") && !HttpContext.User.Claims.Any(c => c.Type == "scp");
        }
    }
    
  3. Fügen Sie eine Hilfsfunktion hinzu, die feststellt, ob die gestellte Anforderung genügend Berechtigungen enthält, um die beabsichtigte Aktion auszuführen. Überprüfen Sie, ob die App die Anforderung im eigenen Namen stellt oder ob die App den Aufruf im Namen eines Benutzers oder einer Benutzerin tätigt, der*die Besitzer*in der betreffenden Ressource ist, indem wir die Benutzer-ID überprüfen.

    private bool RequestCanAccessToDo(Guid userId)
        {
            return IsAppMakingRequest() || (userId == GetUserId());
        }
    
    private Guid GetUserId()
        {
            Guid userId;
            if (!Guid.TryParse(HttpContext.User.GetObjectId(), out userId))
            {
                throw new Exception("User ID is not valid.");
            }
            return userId;
        }
    
  4. Fügen Sie die Berechtigungsdefinitionen ein, um Routen zu schützen. Schützen Sie Ihre API, indem Sie das Attribut [Authorize] zur Controllerklasse hinzufügen. Dadurch wird sichergestellt, dass die Controlleraktionen nur aufgerufen werden können, wenn die API mit einer autorisierten Identität aufgerufen wird. Die Berechtigungsdefinitionen legen fest, welche Arten von Berechtigungen zur Durchführung dieser Aktionen erforderlich sind.

    [Authorize]
    [Route("api/[controller]")]
    [ApiController]
    public class ToDoListController: ControllerBase{...}
    

    Fügen Sie Berechtigungen zu den GET- und POST-Endpunkten hinzu. Dazu verwenden Sie die Methode RequiredScopeOrAppPermission, die Teil des Namespace Microsoft.Identity.Web.Resource ist. Anschließend übergeben Sie Bereiche und Berechtigungen über die Attribute RequiredScopesConfigurationKey und RequiredAppPermissionsConfigurationKey an diese Methode.

    [HttpGet]
    [RequiredScopeOrAppPermission(
        RequiredScopesConfigurationKey = "AzureAD:Scopes:Read",
        RequiredAppPermissionsConfigurationKey = "AzureAD:AppPermissions:Read"
    )]
    public async Task<IActionResult> GetAsync()
    {
        var toDos = await _toDoContext.ToDos!
            .Where(td => RequestCanAccessToDo(td.Owner))
            .ToListAsync();
    
        return Ok(toDos);
    }
    
    [HttpPost]
    [RequiredScopeOrAppPermission(
        RequiredScopesConfigurationKey = "AzureAD:Scopes:Write",
        RequiredAppPermissionsConfigurationKey = "AzureAD:AppPermissions:Write"
    )]
    public async Task<IActionResult> PostAsync([FromBody] ToDo toDo)
    {
        // Only let applications with global to-do access set the user ID or to-do's
        var ownerIdOfTodo = IsAppMakingRequest() ? toDo.Owner : GetUserId();
    
        var newToDo = new ToDo()
        {
            Owner = ownerIdOfTodo,
            Description = toDo.Description
        };
    
        await _toDoContext.ToDos!.AddAsync(newToDo);
        await _toDoContext.SaveChangesAsync();
    
        return Created($"/todo/{newToDo!.Id}", newToDo);
    }
    

Konfigurieren der API-Middleware für die Verwendung des Controllers

Als Nächstes konfigurieren wir die Anwendung so, dass controller für die Verarbeitung von HTTP-Anforderungen erkannt und verwendet werden. Öffnen Sie die program.cs Datei, und fügen Sie den folgenden Code hinzu, um die Controllerdienste im Container zum Einfügen von Abhängigkeiten zu registrieren.


builder.Services.AddControllers();

var app = builder.Build();
app.MapControllers();

app.Run();

Im vorherigen Codeausschnitt bereitet die AddControllers()-Methode die Anwendung auf die Verwendung von Controllern vor, indem die erforderlichen Dienste registriert werden, während MapControllers() die Controllerrouten zugeordnet werden, um eingehende HTTP-Anforderungen zu verarbeiten.

Ihre API ausführen

Führen Sie Ihre API aus, um sicherzustellen, dass sie ohne Fehler mit dem Befehl dotnet runausgeführt wird. Wenn Sie das HTTPS-Protokoll auch während der Testphase verwenden möchten, müssen Sie dem Entwicklungszertifikat von .NET vertrauen.

  1. Starten Sie die Anwendung, indem Sie Folgendes im Terminal eingeben:

    dotnet run
    
  2. Eine Ausgabe ähnlich der folgenden sollte im Terminal angezeigt werden. Dadurch wird bestätigt, dass die Anwendung unter http://localhost:{port} ausgeführt wird und auf Anforderungen lauscht.

    Building...
    info: Microsoft.Hosting.Lifetime[0]
        Now listening on: http://localhost:{port}
    info: Microsoft.Hosting.Lifetime[0]
        Application started. Press Ctrl+C to shut down.
    ...
    

Die Webseite http://localhost:{host} zeigt eine Ausgabe ähnlich der folgenden Abbildung an. Dies liegt daran, dass die API ohne Authentifizierung aufgerufen wird. Informationen zum Zugreifen auf eine geschützte Web-API finden Sie in den nächsten Schritten , um einen autorisierten Aufruf auszuführen.

Screenshot, der den Fehler 401 anzeigt, wenn die Webseite gestartet wird.

Ein vollständiges Beispiel für diesen API-Code finden Sie in der Beispieldatei.

Nächste Schritte