Verwenden von Identity zum Schützen eines Web-API-Back-Ends für SPAs

Hinweis

Dies ist nicht die neueste Version dieses Artikels. Informationen zum aktuellen Release finden Sie in der .NET 8-Version dieses Artikels.

Wichtig

Diese Informationen beziehen sich auf ein Vorabversionsprodukt, das vor der kommerziellen Freigabe möglicherweise noch wesentlichen Änderungen unterliegt. Microsoft gibt keine Garantie, weder ausdrücklich noch impliziert, hinsichtlich der hier bereitgestellten Informationen.

Informationen zum aktuellen Release finden Sie in der .NET 8-Version dieses Artikels.

ASP.NET Core Identity stellt APIs für die Authentifizierung, Autorisierung und Identitätsverwaltung bereit. Die APIs ermöglichen es, Endpunkte eines Web-API-Back-Ends mit cookie-basierter Authentifizierung zu schützen. Für Clients, die keine cookies verwenden können, steht eine tokenbasierte Option zur Verfügung.

In diesem Artikel erfahren Sie, wie Sie Identity verwenden, um ein Web-API-Back-End für SPAs wie Angular-, React- und Vue-Apps zu schützen. Die gleichen Back-End-APIs können zum Schützen von Blazor WebAssembly-Apps verwendet werden.

Voraussetzungen

Die in diesem Artikel gezeigten Schritte fügen einer ASP.NET Core-Web-API-App Authentifizierungs- und Autorisierungsfunktionen hinzu, für die Folgendes gilt:

  • noch nicht für die Authentifizierung konfiguriert ist
  • Sie ist auf net8.0 oder höhere Versionen ausgerichtet.
  • Sie kann eine minimale API oder eine controllerbasierte API sein.

Einige der Testanweisungen in diesem Artikel verwenden die Swagger-Benutzeroberfläche, die in der Projektvorlage enthalten ist. Die Swagger-Benutzeroberfläche ist nicht erforderlich, um Identity mit einem Web-API-Back-End zu verwenden.

Installieren von NuGet-Paketen

Installieren Sie die folgenden NuGet-Pakete:

Verwenden Sie für den schnellstmöglichen Einstieg die In-Memory-Datenbank.

Ändern Sie die Datenbank später in SQLite oder SQL Server, um Benutzerdaten beim Testen oder für die Produktionsverwendung sitzungsübergreifend zu speichern. Dies führt zu einem gewissen Maß an Komplexität im Vergleich zum In-Memory-Modell, da die Datenbank über Migrationen erstellt werden muss, wie im Tutorial Erste Schritte mit EF Core gezeigt.

Installieren Sie diese Pakete über den NuGet-Paket-Manager in Visual Studio oder mithilfe des CLI-Befehls dotnet add package.

Erstellen Sie einen IdentityDbContext.

Fügen Sie eine Klasse namens ApplicationDbContext hinzu, die von IdentityDbContext<TUser> erbt:

using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;

public class ApplicationDbContext : IdentityDbContext<IdentityUser>
{
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) :
        base(options)
    { }
}

Der gezeigte Code enthält einen speziellen Konstruktor, mit dem die Datenbank für verschiedene Umgebungen konfiguriert werden kann.

Fügen Sie bei Bedarf eine oder mehrere der folgenden using-Direktiven hinzu, wenn Sie den in diesen Schritten gezeigten Code hinzufügen.

using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;

Konfigurieren des EF Core-Kontexts

Wie bereits erwähnt, ist es am einfachsten, zunächst die In-Memory-Datenbank zu verwenden. Beim In-Memory-Modell beginnt jede Ausführung mit einer neuen Datenbank, und es müssen keine Migrationen verwendet werden. Fügen Sie nach dem Aufruf von WebApplication.CreateBuilder(args) den folgenden Code hinzu, um Identity für die Verwendung einer In-Memory-Datenbank zu konfigurieren:

builder.Services.AddDbContext<ApplicationDbContext>(
    options => options.UseInMemoryDatabase("AppDb"));

Ändern Sie die Datenbank später in SQLite oder SQL Server, um Benutzerdaten beim Testen oder für die Verwendung in der Produktion sitzungsübergreifend zu speichern.

Hinzufügen von Identity-Diensten zum Container

Nach dem Aufruf von WebApplication.CreateBuilder(args) muss AddAuthorization aufgerufen werden, um dem DI-Container (Dependency Injection) Dienste hinzuzufügen:

builder.Services.AddAuthorization();

Aktivieren von Identity-APIs

Nach dem Aufruf von WebApplication.CreateBuilder(args) müssen AddIdentityApiEndpoints<TUser>(IServiceCollection) und AddEntityFrameworkStores<TContext>(IdentityBuilder) aufgerufen werden.

builder.Services.AddIdentityApiEndpoints<IdentityUser>()
    .AddEntityFrameworkStores<ApplicationDbContext>();

Standardmäßig werden sowohl cookies als auch proprietäre Token aktiviert. Cookies und Token werden bei der Anmeldung ausgegeben, wenn der Abfragezeichenfolgenparameter useCookies am Anmeldeendpunkt true lautet.

Zuordnen von Identity-Routen

Nach dem Aufruf von builder.Build() muss MapIdentityApi<TUser>(IEndpointRouteBuilder) aufgerufen werden, um die Identity-Endpunkte zuzuordnen:

app.MapIdentityApi<IdentityUser>();

Sichere ausgewählte Endpunkte

Verwenden Sie zum Schützen eines Endpunkts die RequireAuthorization-Erweiterungsmethode für den Map{Method}-Aufruf, der die Route definiert. Beispiel:

app.MapGet("/weatherforecast", (HttpContext httpContext) =>
{
    var forecast = Enumerable.Range(1, 5).Select(index =>
        new WeatherForecast
        {
            Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
            TemperatureC = Random.Shared.Next(-20, 55),
            Summary = summaries[Random.Shared.Next(summaries.Length)]
        })
        .ToArray();
    return forecast;
})
.WithName("GetWeatherForecast")
.WithOpenApi()
.RequireAuthorization();

Die RequireAuthorization-Methode kann auch für Folgendes verwendet werden:

  • Schützen von Swagger-Benutzeroberflächenendpunkten, wie im folgenden Beispiel gezeigt:

    app.MapSwagger().RequireAuthorization();
    
  • Schützen mit einem bestimmten Anspruch oder einer bestimmten Berechtigung, wie im folgenden Beispiel gezeigt:

    .RequireAuthorization("Admin");
    

Schützen Sie die Endpunkte in einem controllerbasierten Web-API-Projekt, indem Sie das Attribut [Authorize] auf einen Controller oder eine Aktion anwenden.

Testen der API

Eine schnelle Möglichkeit zum Testen der Authentifizierung besteht darin, die In-Memory-Datenbank und die Swagger-Benutzeroberfläche zu verwenden, die in der Projektvorlage enthalten ist. Die folgenden Schritte zeigen, wie Sie die API mit der Swagger-Benutzeroberfläche testen. Vergewissern Sie sich, dass die Endpunkte der Swagger-Benutzeroberfläche nicht geschützt sind.

Versuchen, auf einen geschützten Endpunkt zuzugreifen

  • Führen Sie die App aus, und navigieren Sie zur Swagger-Benutzeroberfläche.
  • Erweitern Sie einen geschützten Endpunkt (z. B. /weatherforecast) in einem Projekt, das von der Web-API-Vorlage erstellt wurde.
  • Wählen Sie Ausprobieren aus.
  • Wählen Sie Execute(Ausführen). Die Antwort lautet: 401 - not authorized.

Testen der Registrierung

  • Erweitern Sie /register, und wählen Sie Ausprobieren aus.

  • Im Abschnitt Parameter der Benutzeroberfläche wird ein exemplarischer Anforderungstext angezeigt:

    {
      "email": "string",
      "password": "string"
    }
    
  • Ersetzen Sie „string“ durch eine gültige E-Mail-Adresse und ein gültiges Kennwort, und wählen Sie dann Ausführen aus.

    Um den Standardregeln für Kennwörter zu entsprechen, muss das Kennwort mindestens sechs Zeichen lang sein und mindestens eins der folgenden Zeichen enthalten:

    • Großbuchstabe
    • Kleinbuchstabe
    • Numerische Ziffer
    • Nicht alphanumerisches Zeichen

    Wenn Sie eine ungültige E-Mail-Adresse oder ein ungültiges Kennwort eingeben, enthält das Ergebnis die Überprüfungsfehler. Hier sehen Sie ein Beispiel für einen Antworttext mit Überprüfungsfehlern:

    {
      "type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
      "title": "One or more validation errors occurred.",
      "status": 400,
      "errors": {
        "PasswordTooShort": [
          "Passwords must be at least 6 characters."
        ],
        "PasswordRequiresNonAlphanumeric": [
          "Passwords must have at least one non alphanumeric character."
        ],
        "PasswordRequiresDigit": [
          "Passwords must have at least one digit ('0'-'9')."
        ],
        "PasswordRequiresLower": [
          "Passwords must have at least one lowercase ('a'-'z')."
        ]
      }
    }
    

    Die Fehler werden im Format ProblemDetails zurückgegeben, sodass der Client sie analysieren und bei Bedarf Validierungsfehler anzeigen kann.

    Eine erfolgreiche Registrierung führt zu einer Antwort vom Typ 200 - OK.

Testen der Anmeldung

  • Erweitern Sie /login, und wählen Sie Ausprobieren aus. Der exemplarische Anforderungstext enthält zwei zusätzliche Parameter:

    {
      "email": "string",
      "password": "string",
      "twoFactorCode": "string",
      "twoFactorRecoveryCode": "string"
    }
    

    Die zusätzlichen JSON-Eigenschaften werden für dieses Beispiel nicht benötigt und können gelöscht werden. Setzen Sie useCookies auf true.

  • Ersetzen Sie „string“ durch die E-Mail-Adresse und das Kennwort, die Sie bei der Registrierung verwendet haben, und wählen Sie anschließend Ausführen aus.

    Eine erfolgreiche Anmeldung führt zu einer Antwort vom Typ 200 - OK mit einem cookie im Antwortheader.

Erneutes Testen des geschützten Endpunkts

Führen Sie nach einer erfolgreichen Anmeldung erneut den geschützten Endpunkt aus. Das cookie für die Authentifizierung wird automatisch zusammen mit der Anforderung gesendet, und der Endpunkt wird autorisiert. Die Cookie-basierte Authentifizierung ist sicher in den Browser integriert und funktioniert reibungslos.

Testen mit browserfremden Clients

Einige Webclients enthalten möglicherweise standardmäßig keine cookies im Header:

  • Wenn Sie ein Tool zum Testen von APIs verwenden, müssen cookies möglicherweise in den Einstellungen aktiviert werden.

  • Die JavaScript-fetch-API enthält standardmäßig keine cookies. Aktivieren Sie sie, indem Sie credentials in den Optionen auf den Wert include festlegen.

  • Bei einer in einer Blazor WebAssembly-App ausgeführten HttpClient-Instanz muss HttpRequestMessage Anmeldeinformationen enthalten. Beispiel:

    request.SetBrowserRequestCredential(BrowserRequestCredentials.Include);
    

Verwenden der tokenbasierten Authentifizierung

Für Clients, die keine cookies unterstützen, stellt die Anmelde-API einen Parameter zum Anfordern von Token bereit. Ein benutzerdefiniertes Token (also ein proprietäres Token der ASP.NET Core-Identitätsplattform) wird ausgegeben und kann zum Authentifizieren nachfolgender Anforderungen verwendet werden. Das Token wird im Authorization-Header als Bearertoken übergeben. Außerdem wird ein Aktualisierungstoken bereitgestellt. Mit diesem Token kann die Anwendung ein neues Token anfordern, wenn das alte abläuft, ohne dass sich die Benutzer*innen erneut anmelden müssen.

Die Token sind standardmäßig keine JSON-Webtoken (JWTs). Die Verwendung benutzerdefinierter Token ist beabsichtigt, da die integrierte Identity-API in erster Linie für einfache Szenarien vorgesehen ist. Die Tokenoption ist nicht als vollständiger Identitätsdienstanbieter oder Tokenserver gedacht, sondern eine Alternative zur cookie-Option für Clients, die keine cookies verwenden können.

Um die tokenbasierte Authentifizierung zu verwenden, legen Sie den useCookies-Abfragezeichenfolgenparameter beim Aufrufen des /login-Endpunkts auf false fest. Token verwenden das Bearerauthentifizierungsschema. Wenn Sie das vom Aufruf von /loginzurückgegebene Token verwenden, sollten nachfolgende Aufrufe von geschützten Endpunkten den Header Authorization: Bearer <token> hinzufügen, wobei <token> das Zugriffstoken ist. Weitere Informationen finden Sie unter Verwenden des POST /login-Endpunkts weiter unten in diesem Artikel.

Abmelden

Um Benutzer*innen eine Möglichkeit zum Abmelden bereitzustellen, definieren Sie einen /logout-Endpunkt wie im folgenden Beispiel:

app.MapPost("/logout", async (SignInManager<IdentityUser> signInManager,
    [FromBody] object empty) =>
{
    if (empty != null)
    {
        await signInManager.SignOutAsync();
        return Results.Ok();
    }
    return Results.Unauthorized();
})
.WithOpenApi()
.RequireAuthorization();

Stellen Sie beim Aufrufen dieses Endpunkts ein leeres JSON-Objekt ({}) im Anforderungstext bereit. Der folgende Code ist ein Beispiel für einen Aufruf des Abmeldeendpunkts:

public signOut() {
  return this.http.post('/logout', {}, {
    withCredentials: true,
    observe: 'response',
    responseType: 'text'

Die MapIdentityApi<TUser>-Endpunkte

Der Aufruf von MapIdentityApi<TUser> fügt der App die folgenden Endpunkte hinzu:

Verwenden des POST /register-Endpunkts

Der Anforderungstext muss über Email- und Password-Eigenschaften verfügen:

{
  "email": "string",
  "password": "string",
}

Weitere Informationen finden Sie unter:

Verwenden des POST /login-Endpunkts

Im Anforderungstext sind Email und Password erforderlich. Wenn die Zwei-Faktor-Authentifizierung (2FA) aktiviert ist, ist entweder TwoFactorCode oder TwoFactorRecoveryCode erforderlich. Wenn 2FA nicht aktiviert ist, lassen Sie sowohl twoFactorCode als auch twoFactorRecoveryCode weg. Weitere Informationen finden Sie unter Verwenden des POST /manage/2fa-Endpunkts weiter unten in diesem Artikel.

Hier ist ein Anforderungstextbeispiel mit nicht aktivierter 2FA:

{
  "email": "string",
  "password": "string"
}

Hier sind Anforderungstextbeispiele mit aktivierter 2FA:

  • {
      "email": "string",
      "password": "string",
      "twoFactorCode": "string",
    }
    
  • {
      "email": "string",
      "password": "string",
      "twoFactorRecoveryCode": "string"
    }
    

Der Endpunkt erwartet einen Abfragezeichenfolgenparameter:

  • useCookies: Für die cookie-basierte Authentifizierung auf true festgelegt. Legen Sie diesen Wert auf false fest, oder lassen Sie ihn für die tokenbasierte Authentifizierung weg.

Weitere Informationen zur cookie-basierten Authentifizierung finden Sie unter Testen der Anmeldung weiter oben in diesem Artikel.

Tokenbasierte Authentifizierung

Wenn useCookies gleich false ist oder weggelassen wird, wird die tokenbasierte Authentifizierung aktiviert. Der Antworttext enthält die folgenden Eigenschaften:

{
  "tokenType": "string",
  "accessToken": "string",
  "expiresIn": 0,
  "refreshToken": "string"
}

Weitere Informationen zu diesen Eigenschaften finden Sie unter AccessTokenResponse.

Fügen Sie das Zugriffstoken in einen Header ein, um authentifizierte Anforderungen vorzunehmen, wie im folgenden Beispiel gezeigt.

Authorization: Bearer {access token}

Wenn das Zugriffstoken bald abläuft, rufen Sie den /refresh-Endpunkt auf.

Verwenden des POST /refresh-Endpunkts

Dieser ist nur zur Verwendung mit tokenbasierter Authentifizierung vorgesehen. Er ruft ein neues Zugriffstoken ab, ohne dass Benutzer*innen gezwungen werden, sich erneut anzumelden. Rufen Sie diesen Endpunkt auf, wenn das Zugriffstoken bald abläuft.

Der Anforderungstext enthält nur RefreshToken. Hier ist ein Anforderungstextbeispiel:

{
  "refreshToken": "string"
}

Wenn der Aufruf erfolgreich ist, ist der Antworttext eine neue AccessTokenResponse, wie im folgenden Beispiel gezeigt:

{
  "tokenType": "string",
  "accessToken": "string",
  "expiresIn": 0,
  "refreshToken": "string"
}

Verwenden des GET /confirmEmail-Endpunkts

Wenn Identity für die E-Mail-Bestätigung eingerichtet ist, sendet ein erfolgreicher Aufruf des /register-Endpunkts eine E-Mail, die einen Link zum /confirmEmail-Endpunkt enthält. Der Link enthält die folgenden Abfragezeichenfolgenparameter:

  • userId
  • code
  • changedEmail: nur enthalten, wenn der oder die Benutzer*in die E-Mail-Adresse während der Registrierung geändert hat

Standardmäßig lautet der E-Mail-Betreff „Bestätigen Sie Ihre E-Mail-Adresse“, und der E-Mail-Textkörper sieht wie im folgenden Beispiel aus:

 Please confirm your account by <a href='https://contoso.com/confirmEmail?userId={user ID}&code={generated code}&changedEmail={new email address}'>clicking here</a>.

Wenn die RequireConfirmedEmail-Eigenschaft auf true festgelegt ist, können sich Benutzer*innen erst anmelden, wenn die E-Mail-Adresse durch Klicken auf den Link in der E-Mail bestätigt wird. Der /confirmEmail-Endpunkt:

  • bestätigt die E-Mail-Adresse und ermöglicht es dem oder der Benutzer*in, sich anzumelden
  • gibt den Text „Vielen Dank für die Bestätigung Ihrer E-Mail-Adresse“ im Antworttext zurück

Um Identity für die E-Mail-Bestätigung einzurichten, fügen Sie Code in Program.cs hinzu, um RequireConfirmedEmail auf true festzulegen, und fügen Sie eine Klasse hinzu, die IEmailSender im DI-Container implementiert. Beispiel:

builder.Services.Configure<IdentityOptions>(options =>
{
    options.SignIn.RequireConfirmedEmail = true;
});

builder.Services.AddTransient<IEmailSender, EmailSender>();

Im vorherigen Beispiel ist EmailSender eine Klasse, die IEmailSender implementiert. Weitere Informationen, einschließlich eines Beispiels für eine Klasse, die IEmailSender implementiert, finden Sie unter Kontobestätigung und Kennwortwiederherstellung in ASP.NET Core.

Verwenden des POST /resendConfirmationEmail-Endpunkts

Dieser sendet nur eine E-Mail, wenn die Adresse für eine*n registrierte*n Benutzer*in gültig ist.

Der Anforderungstext enthält nur Email. Hier ist ein Anforderungstextbeispiel:

{
  "email": "string"
}

Weitere Informationen finden Sie unter Verwenden des GET /confirmEmail-Endpunkts weiter oben in diesem Artikel.

Verwenden des POST /forgotPassword-Endpunkts

Dieser generiert eine E-Mail, die einen Kennwortzurücksetzungscode enthält. Senden Sie diesen Code mit einem neuen Kennwort an /resetPassword.

Der Anforderungstext enthält nur Email. Ein Beispiel:

{
  "email": "string"
}

Informationen zum Aktivieren von Identity zum Senden von E-Mails finden Sie unter Verwenden des GET /confirmEmail-Endpunkts.

Verwenden des POST /resetPassword-Endpunkts

Rufen Sie diesen Endpunkt nach dem Abruf eines Zurücksetzungscodes auf, indem Sie den /forgotPassword-Endpunkt aufrufen.

Der Anforderungstext erfordert Email, ResetCode und NewPassword. Ein Beispiel:

{
  "email": "string",
  "resetCode": "string",
  "newPassword": "string"
}

Verwenden des POST /manage/2fa-Endpunkts

Dieser konfiguriert die Zwei-Faktor-Authentifizierung (2FA) für den oder die Benutzer*in. Wenn die 2FA aktiviert ist, ist für die erfolgreiche Anmeldung zusätzlich zur E-Mail-Adresse und dem Kennwort ein Code erforderlich, der von einer Authentifikator-App generiert wird.

2FA aktivieren

So aktivieren Sie die 2FA für den oder die aktuelle*n Benutzer*in:

  • Rufen Sie den /manage/2fa-Endpunkt auf, und senden Sie ein leeres JSON-Objekt ({}) im Anforderungstext.

  • Der Antworttext stellt SharedKey zusammen mit einigen anderen Eigenschaften bereit, die zu diesem Zeitpunkt nicht benötigt werden. Der freigegebene Schlüssel wird zum Einrichten der Authentifikator-App verwendet. Beispiel für einen Antworttext:

    {
      "sharedKey": "string",
      "recoveryCodesLeft": 0,
      "recoveryCodes": null,
      "isTwoFactorEnabled": false,
      "isMachineRemembered": false
    }
    
  • Verwenden Sie den freigegebenen Schlüssel, um ein zeitbasiertes Einmalkennwort (TOTP) abzurufen. Weitere Informationen finden Sie unter Aktivieren der QR-Code-Generierung für TOTP-Authentifikator-Apps in ASP.NET Core.

  • Rufen Sie den /manage/2fa-Endpunkt auf, und senden Sie das TOTP und "enable": true im Anforderungstext. Beispiel:

    {
      "enable": true,
      "twoFactorCode": "string"
    }
    
  • Der Antworttext bestätigt, dass IsTwoFactorEnabled zutrifft und RecoveryCodesbereitstellt. Die Wiederherstellungscodes werden für die Anmeldung verwendet, wenn die Authentifikator-App nicht verfügbar ist. Beispiel für den Antworttext nach erfolgreicher Aktivierung der 2FA:

    {
      "sharedKey": "string",
      "recoveryCodesLeft": 10,
      "recoveryCodes": [
        "string",
        "string",
        "string",
        "string",
        "string",
        "string",
        "string",
        "string",
        "string",
        "string"
      ],
      "isTwoFactorEnabled": true,
      "isMachineRemembered": false
    }
    

Anmelden mit 2FA

Rufen Sie den /login-Endpunkt auf, und übermitteln Sie die E-Mail-Adresse, das Kennwort und das TOTP im Anforderungstext. Beispiel:

{
  "email": "string",
  "password": "string",
  "twoFactorCode": "string"
}

Wenn der oder die Benutzer*in keinen Zugriff auf die Authentifikator-App hat, kann die Anmeldung erfolgen, indem der /login-Endpunkt mit einem der Wiederherstellungscodes aufgerufen wird, die bei der Aktivierung der 2FA bereitgestellt wurden. Der Anforderungstext sieht wie das folgende Beispiel aus:

{
  "email": "string",
  "password": "string",
  "twoFactorRecoveryCode": "string"
}

Zurücksetzen der Wiederherstellungscodes

Rufen Sie diesen Endpunkt auf, um neue Wiederherstellungscodes zu erhalten, wobei ResetRecoveryCodes auf true festgelegt sein muss. Hier ist ein Anforderungstextbeispiel:

{
  "resetRecoveryCodes": true
}

Zurücksetzen des freigegebenen Schlüssels

Um einen neuen zufälligen freigegebenen Schlüssel abzurufen, rufen Sie diesen Endpunkt auf, wobei ResetSharedKey auf true festgelegt sein muss. Hier ist ein Anforderungstextbeispiel:

{
  "resetSharedKey": true
}

Durch das Zurücksetzen des Schlüssels wird die erforderliche Zwei-Faktor-Authentifizierung für den oder die authentifierende*n Benutzer*in automatisch deaktiviert, bis sie durch eine nachfolgende Anforderung reaktiviert wird.

Vergessen des Computers

Rufen Sie diesen Endpunkt auf, wobei ForgetMachine auf „true“ festgelegt sein muss, um das cookie-Flag „Anmeldedaten speichern“ zu löschen, falls vorhanden. Hier ist ein Anforderungstextbeispiel:

{
  "forgetMachine": true
}

Dieser Endpunkt hat keine Auswirkungen auf die tokenbasierte Authentifizierung.

Verwenden des GET /manage/info-Endpunkts

Dieser ruft die E-Mail-Adresse und den E-Mail-Bestätigungsstatus des oder der angemeldeten Benutzer*in ab. Ansprüche wurden aus Sicherheitsgründen bei diesem Endpunkt weggelassen. Wenn Ansprüche erforderlich sind, verwenden Sie die serverseitigen APIs, um einen Endpunkt für Ansprüche einzurichten. Statt alle Ansprüche der Benutzer*innen freizugeben, können Sie alternativ einen Überprüfungsendpunkt bereitstellen, der einen Anspruch akzeptiert, und antwortet, ob der oder die Benutzer*in über diesen verfügt.

Für die Anforderung sind keine Parameter erforderlich. Der Antworttext enthält die Eigenschaften Email und IsEmailConfirmed, wie im folgenden Beispiel gezeigt:

{
  "email": "string",
  "isEmailConfirmed": true
}

Verwenden des POST /manage/info-Endpunkts

Dieser aktualisiert die E-Mail-Adresse und das Kennwort des oder der angemeldeten Benutzer*in. Übermitteln Sie NewEmail, NewPassword und OldPassword im Anforderungstext, wie im folgenden Beispiel gezeigt:

{
  "newEmail": "string",
  "newPassword": "string",
  "oldPassword": "string"
}

Es folgt ein Beispiel für den Antworttext:

{
  "email": "string",
  "isEmailConfirmed": false
}

Siehe auch

Weitere Informationen finden Sie in den folgenden Ressourcen:

Die ASP.NET Core-Vorlagen bieten eine Authentifizierung in Single-Page-Webanwendungen (SPAs) unter Verwendung der Unterstützung für die API-Autorisierung. Die ASP.NET Core Identity für die Authentifizierung und zum Speichern von Benutzer*innen wird dabei mit Duende Identity Server für die Implementierung von OpenID Connect kombiniert.

Wichtig

Duende Software erhebt ggf. eine Lizenzgebühr für die Nutzung von Duende Identity Server in der Produktion. Weitere Informationen finden Sie unter Migrieren von ASP.NET Core 5.0 zu 6.0.

Den Angular- und React-Projektvorlagen wurde ein Authentifizierungsparameter hinzugefügt, der dem Authentifizierungsparameter in den Projektvorlagen für Webanwendung (Model View Controller) (MVC) und Webanwendung (Razor Pages) ähnelt. Die zulässigen Parameterwerte sind None und Individual. Die Projektvorlage für React.js und Redux unterstützt den Authentifizierungsparameter derzeit nicht.

Erstellen einer App mit Unterstützung für die API-Autorisierung

Die Benutzerauthentifizierung und -autorisierung kann sowohl mit Angular- als auch mit React-SPAs verwendet werden. Öffnen Sie eine Befehlsshell, und führen Sie den folgenden Befehl aus:

Angular:

dotnet new angular -au Individual

React:

dotnet new react -au Individual

Mit dem obigen Befehl wird eine ASP.NET Core-App mit einem ClientApp-Verzeichnis erstellt, das die Single-Page-Webanwendung enthält.

Allgemeine Beschreibung der ASP.NET Core-Komponenten der App

In den folgenden Abschnitten werden Ergänzungen zum Projekt erläutert, wenn die Authentifizierungsunterstützung eingeschlossen wird:

Program.cs

Die folgenden Codebeispiele basieren auf dem NuGet-Paket Microsoft.AspNetCore.ApiAuthorization.IdentityServer. In den Beispielen wird die API-Authentifizierung und -Autorisierung mithilfe der Erweiterungsmethoden AddApiAuthorization und AddIdentityServerJwt konfiguriert. Projekte, die die Projektvorlagen für React- oder Angular-SPAs mit Authentifizierung verwenden, enthalten einen Verweis auf dieses Paket.

dotnet new angular -au Individual generiert die folgende Datei Program.cs:

using Microsoft.AspNetCore.Authentication;
using Microsoft.EntityFrameworkCore;
using output_directory_name.Data;
using output_directory_name.Models;

var builder = WebApplication.CreateBuilder(args);

var connectionString = builder.Configuration.GetConnectionString("DefaultConnection") ?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found.");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
    options.UseSqlite(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();

builder.Services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true)
    .AddEntityFrameworkStores<ApplicationDbContext>();

builder.Services.AddIdentityServer()
    .AddApiAuthorization<ApplicationUser, ApplicationDbContext>();

builder.Services.AddAuthentication()
    .AddIdentityServerJwt();

builder.Services.AddControllersWithViews();
builder.Services.AddRazorPages();

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseMigrationsEndPoint();
}
else
{
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();

app.UseAuthentication();
app.UseIdentityServer();
app.UseAuthorization();

app.MapControllerRoute(
    name: "default",
    pattern: "{controller}/{action=Index}/{id?}");
app.MapRazorPages();

app.MapFallbackToFile("index.html");

app.Run();

Mit dem vorangehenden Code wird Folgendes konfiguriert:

  • Identity mit der Standardbenutzeroberfläche:

    builder.Services.AddDbContext<ApplicationDbContext>(options =>
        options.UseSqlite(connectionString));
    builder.Services.AddDatabaseDeveloperPageExceptionFilter();
    
    builder.Services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true)
        .AddEntityFrameworkStores<ApplicationDbContext>();
    
  • IdentityServer mit einer zusätzlichen AddApiAuthorization-Hilfsmethode, die einige ASP.NET Core-Standardkonventionen zusätzlich zu IdentityServer einrichtet:

    builder.Services.AddIdentityServer()
        .AddApiAuthorization<ApplicationUser, ApplicationDbContext>();
    
  • Authentifizierung mit einer zusätzlichen AddIdentityServerJwt-Hilfsmethode, die die App so konfiguriert, dass sie von Identity Server generierte JWT-Token überprüft:

    builder.Services.AddAuthentication()
    .AddIdentityServerJwt();
    
  • Die Authentifizierungsmiddleware, die für die Überprüfung der Anforderungsanmeldeinformationen und für das Festlegen des Benutzers auf den Anforderungskontext verantwortlich ist:

    app.UseAuthentication();
    
  • Die IdentityServer-Middleware, die die OpenID Connect-Endpunkte bereitstellt:

    app.UseIdentityServer();
    

Azure App Service für Linux

Geben Sie für Azure App Service-Bereitstellungen unter Linux den Aussteller explizit an:

builder.Services.Configure<JwtBearerOptions>(
    IdentityServerJwtConstants.IdentityServerJwtBearerScheme, 
    options =>
    {
        options.Authority = "{AUTHORITY}";
    });

Im obigen Code ist der Platzhalter {AUTHORITY} die Authority, die bei OpenID Connect-Aufrufen verwendet werden soll.

Beispiel:

options.Authority = "https://contoso-service.azurewebsites.net";

AddApiAuthorization

Diese Hilfsmethode konfiguriert IdentityServer für die Verwendung der unterstützten Konfiguration. IdentityServer ist ein leistungsfähiges und erweiterbares Framework für Überlegungen zum Thema „App-Sicherheit“. Dies erhöht gleichzeitig die Komplexität für die meisten gängigen Szenarien unnötig. Daher werden mehrere Konventionen und Konfigurationsoptionen bereitgestellt, die sich gut als Ausgangspunkt eignen. Wenn sich Ihre Anforderungen an die Authentifizierung ändern, bietet IdentityServer eine Vielzahl leistungsfähiger Funktionen, mit denen Sie die Authentifizierung genau an Ihre Anforderungen anpassen können.

AddIdentityServerJwt

Diese Hilfsprogrammmethode konfiguriert ein Richtlinienschema für die App als Standardauthentifizierungshandler. Die Richtlinie ist so konfiguriert, dass Identity alle an beliebige Unterpfade im Identity-URL-Raum „/Identity“ weitergeleiteten Anforderungen verarbeiten kann. JwtBearerHandler verarbeitet alle anderen Anforderungen. Darüber hinaus registriert diese Methode eine <<ApplicationName>>API-API-Ressource bei IdentityServer mit dem Standardbereich <<ApplicationName>>API und konfiguriert die Middleware für JWT-Bearertoken, um von IdentityServer für die App ausgestellte Token zu überprüfen.

WeatherForecastController

Beachten Sie in der Datei, dass das auf die Klasse angewandte [Authorize]-Attribut angibt, dass die Benutzer*innen basierend auf der Standardrichtlinie autorisiert werden müssen, um auf die Ressource zuzugreifen. Die Standardautorisierungsrichtlinie wird für die Verwendung des Standardauthentifizierungsschemas konfiguriert, das von AddIdentityServerJwt für das oben angegebene Richtlinienschema eingerichtet wurde, sodass der mit einer solchen Hilfsmethode konfigurierte JwtBearerHandler zum Standardhandler für Anforderungen an die App wird.

ApplicationDbContext

Beachten Sie in der Datei, dass derselbe DbContext in Identity verwendet wird, mit der Ausnahme, dass er ApiAuthorizationDbContext erweitert (eine stärker abgeleitete Klasse von IdentityDbContext), um das Schema für IdentityServer einzuschließen.

Für eine vollständige Kontrolle des Datenbankschemas wird von einer der verfügbaren Identity-DbContext-Klassen geerbt, und der Kontext wird so konfiguriert, dass er das Identity-Schema einschließt, indem builder.ConfigurePersistedGrantContext(_operationalStoreOptions.Value) in der OnModelCreating-Methode aufgerufen wird.

OidcConfigurationController

Beachten Sie in der Datei den Endpunkt, der für die Bereitstellung der OIDC-Parameter bereitgestellt wird, die der Client verwenden muss.

appsettings.json

In der Datei appsettings.json im Projektstamm gibt es einen neuen Abschnitt IdentityServer, in dem die Liste der konfigurierten Clients beschrieben wird. Im folgenden Beispiel gibt es einen einzelnen Client. Der Clientname entspricht dem App-Namen, und er wird durch Konventionen dem OAuth-ClientId-Parameter zugeordnet. Das Profil gibt den App-Typ an, der konfiguriert wird. Es wird intern verwendet, um Konventionen zu etablieren, die den Konfigurationsprozess für den Server vereinfachen. Es sind mehrere Profile verfügbar, wie im Abschnitt Anwendungsprofile erläutert.

"IdentityServer": {
  "Clients": {
    "angularindividualpreview3final": {
      "Profile": "IdentityServerSPA"
    }
  }
}

appsettings.Development.json

In der Datei appsettings.Development.json im Projektstamm befindet sich ein Abschnitt IdentityServer, in dem der zum Signieren von Token verwendete Schlüssel beschrieben wird. Bei der Bereitstellung in der Produktion muss ein Schlüssel zusammen mit der App bereitgestellt werden, wie im Abschnitt Bereitstellen in der Produktion erläutert.

"IdentityServer": {
  "Key": {
    "Type": "Development"
  }
}

Allgemeine Beschreibung der Angular-App

Die Unterstützung für Authentifizierung und API-Autorisierung in der Angular-Vorlage befindet sich in einem eigenen Angular-Modul im Verzeichnis ClientApp/src/api-authorization. Das Modul besteht aus folgenden Elementen:

  • 3 Komponenten:
    • login.component.ts verarbeitet den Anmeldeflow der App.
    • logout.component.ts verarbeitet den Abmeldeflow der App.
    • login-menu.component.ts ist ein Widget, das einen der folgenden Linksätze anzeigt:
      • Benutzerprofilverwaltung und Abmeldelinks, wenn Benutzer*innen authentifiziert werden
      • Registrierungs- und Anmeldelinks, wenn Benutzer*innen nicht authentifiziert werden
  • Ein Routenwächter (AuthorizeGuard), der Routen hinzugefügt werden kann und erzwingt, dass Benutzer*innen authentifiziert werden, bevor die Route besucht wird
  • Ein HTTP-Interceptor (AuthorizeInterceptor), der das Zugriffstoken an ausgehende HTTP-Anforderungen an die API anfügt, wenn Benutzer*innen authentifiziert werden
  • Ein Dienst (AuthorizeService), der die Details auf niedrigerer Ebene des Authentifizierungsprozesses verarbeitet und Informationen zu den authentifizierten Benutzer*innen für die übrige App zur Nutzung verfügbar macht
  • Ein Angular-Modul, das Routen definiert, die den Authentifizierungskomponenten der App zugeordnet sind Es werden die Anmeldemenükomponente, der Interceptor, der Wächter und der Dienst für die Nutzung durch die übrige App verfügbar gemacht.

Allgemeine Beschreibung der React-App

Die Unterstützung für die Authentifizierung und API-Autorisierung in der React-Vorlage befindet sich im Verzeichnis ClientApp/src/components/api-authorization. Sie besteht aus folgenden Elementen:

  • 4 Komponenten:
    • Login.js verarbeitet den Anmeldeflow der App.
    • Logout.js verarbeitet den Abmeldeflow der App.
    • LoginMenu.js ist ein Widget, das einen der folgenden Linksätze anzeigt:
      • Benutzerprofilverwaltung und Abmeldelinks, wenn Benutzer*innen authentifiziert werden
      • Registrierungs- und Anmeldelinks, wenn Benutzer*innen nicht authentifiziert werden
    • AuthorizeRoute.js ist eine Routenkomponente, für die Benutzer*innen authentifiziert werden müssen, bevor die im Component-Parameter angegebene Komponente gerendert wird.
  • Eine exportierte authService-Instanz der AuthorizeService-Klasse, die die Details auf niedrigerer Ebene des Authentifizierungsprozesses verarbeitet und Informationen zu den authentifizierten Benutzer*innen für die übrige App zur Nutzung verfügbar macht

Nachdem Sie nun die wichtigsten Komponenten der Lösung kennengelernt haben, können Sie sich die einzelnen Szenarien für die App genauer ansehen.

Erzwingen der Autorisierung für eine neue API

Standardmäßig ist das System so konfiguriert, dass die Autorisierung für neue APIs problemlos erzwungen werden kann. Erstellen Sie dazu einen neuen Controller, und fügen Sie das [Authorize]-Attribut der Controllerklasse oder einer beliebigen Aktion innerhalb des Controllers hinzu.

Anpassen des API-Authentifizierungshandlers

Um die Konfiguration des JWT-Handlers der API anzupassen, konfigurieren Sie dessen JwtBearerOptions-Instanz:

builder.Services.AddAuthentication()
    .AddIdentityServerJwt();

builder.Services.Configure<JwtBearerOptions>(
    IdentityServerJwtConstants.IdentityServerJwtBearerScheme,
    options =>
    {
        ...
    });

Der JWT-Handler der API löst Ereignisse aus, die das Steuern des Authentifizierungsprozesses mithilfe von JwtBearerEvents ermöglichen. Um Unterstützung für die API-Autorisierung bereitzustellen, registriert AddIdentityServerJwt seine eigenen Ereignishandler.

Um die Behandlung eines Ereignisses anzupassen, umschließen Sie den vorhandenen Ereignishandler nach Bedarf mit zusätzlicher Logik. Beispiel:

builder.Services.Configure<JwtBearerOptions>(
    IdentityServerJwtConstants.IdentityServerJwtBearerScheme,
    options =>
    {
        var onTokenValidated = options.Events.OnTokenValidated;       

        options.Events.OnTokenValidated = async context =>
        {
            await onTokenValidated(context);
            ...
        }
    });

Im obigen Code wird der OnTokenValidated-Ereignishandler durch eine benutzerdefinierte Implementierung ersetzt. Diese Implementierung führt Folgendes aus:

  1. Aufrufen der ursprüngliche Implementierung, die von der API-Autorisierungsunterstützung bereitgestellt wird
  2. Ausführen der eigenen benutzerdefinierten Logik

Schützen einer clientseitigen Route (Angular)

Der Schutz einer clientseitigen Route erfolgt durch Hinzufügen des Autorisierungswächters zur Liste der auszuführenden Wächter beim Konfigurieren einer Route. Sehen Sie sich z. B. an, wie die fetch-data-Route innerhalb des Angular-Moduls der Haupt-App konfiguriert wird:

RouterModule.forRoot([
  // ...
  { path: 'fetch-data', component: FetchDataComponent, canActivate: [AuthorizeGuard] },
])

Es ist wichtig zu erwähnen, dass der Schutz einer Route nicht den eigentlichen Endpunkt selbst schützt (auf den immer noch ein [Authorize]-Attribut angewandt werden muss), sondern dass Benutzer*innen lediglich daran gehindert werden, zur angegebenen clientseitigen Route zu navigieren, wenn sie nicht authentifiziert sind.

Authentifizieren von API-Anforderungen (Angular)

Die Authentifizierung von Anforderungen an APIs, die zusammen mit der App gehostet werden, erfolgt automatisch mithilfe des von der App definierten Interceptors des HTTP-Clients.

Schützen einer clientseitigen Route (React)

Sie schützen eine clientseitige Route, indem Sie die AuthorizeRoute-Komponente anstelle der einfachen Route-Komponente verwenden. Beachten Sie beispielsweise, wie die fetch-data-Route innerhalb der App-Komponente konfiguriert ist:

<AuthorizeRoute path='/fetch-data' component={FetchData} />

Schützen einer Route:

  • Der eigentliche Endpunkt wird nicht geschützt (auf ihn muss immer noch ein [Authorize]-Attribut angewandt werden).
  • Es wird nur verhindert, dass Benutzer*innen zur angegebenen clientseitigen Route navigieren, wenn sie nicht authentifiziert sind.

Authentifizieren von API-Anforderungen (React)

Die Authentifizierung von Anforderungen mit React erfolgt, indem zuerst die authService-Instanz aus dem AuthorizeService importiert wird. Das Zugriffstoken wird wie unten dargestellt von authService abgerufen und an die Anforderung angefügt. In React-Komponenten erfolgt dieser Schritt in der Regel in der componentDidMount-Lebenszyklusmethode oder als Ergebnis einer Benutzerinteraktion.

Importieren des authService in eine Komponente

import authService from './api-authorization/AuthorizeService'

Abrufen und Anfügen des Zugriffstokens an die Antwort

async populateWeatherData() {
  const token = await authService.getAccessToken();
  const response = await fetch('api/SampleData/WeatherForecasts', {
    headers: !token ? {} : { 'Authorization': `Bearer ${token}` }
  });
  const data = await response.json();
  this.setState({ forecasts: data, loading: false });
}

Bereitstellen für die Produktion

Um die App in der Produktion bereitzustellen, müssen die folgenden Ressourcen bereitgestellt werden:

  • Eine Datenbank zum Speichern der Identity-Benutzerkonten und der IdentityServer-Zuweisungen
  • Ein Produktionszertifikat zum Signieren von Token.
    • Für dieses Zertifikat gibt es keine spezifischen Anforderungen. Es kann sich um ein selbstsigniertes Zertifikat oder ein Zertifikat handeln, das über eine Zertifizierungsstelle bereitgestellt wird.
    • Es kann mit Standardtools wie PowerShell oder OpenSSL generiert werden.
    • Es kann im Zertifikatspeicher auf den Zielcomputern installiert oder als PFX-Datei mit einem sicheren Kennwort bereitgestellt werden.

Beispiel: Bereitstellen bei einem anderen Webhostinganbieter als Azure

Erstellen Sie Ihr Zertifikat in Ihrem Webhostingbereich, oder laden Sie es. Ändern Sie dann in der Datei appsettings.json der App den Abschnitt IdentityServer, um Schlüsseldetails einzuschließen. Beispiel:

"IdentityServer": {
  "Key": {
    "Type": "Store",
    "StoreName": "WebHosting",
    "StoreLocation": "CurrentUser",
    "Name": "CN=MyApplication"
  }
}

Im vorherigen Beispiel:

  • StoreName stellt den Namen des Zertifikatspeichers dar, in dem das Zertifikat gespeichert wird. In diesem Fall verweist er auf den Webhostingspeicher.
  • StoreLocation gibt an, von wo das Zertifikat geladen werden soll (in diesem Fall CurrentUser).
  • Name entspricht dem spezifischen Antragsteller des Zertifikats.

Beispiel: Bereitstellen in Azure App Service

In diesem Abschnitt wird die Bereitstellung der App für Azure App Service mithilfe eines im Zertifikatspeicher gespeicherten Zertifikats beschrieben. Um die App so zu ändern, dass sie ein Zertifikat aus dem Zertifikatspeicher lädt, ist ein Dienstplan im Tarif Standard oder höher erforderlich, wenn Sie die App in einem späteren Schritt im Azure-Portal konfigurieren.

Ändern Sie in der Datei appsettings.json der App den Abschnitt IdentityServer, um Schlüsseldetails einzuschließen:

"IdentityServer": {
  "Key": {
    "Type": "Store",
    "StoreName": "My",
    "StoreLocation": "CurrentUser",
    "Name": "CN=MyApplication"
  }
}
  • Der Speichername stellt den Namen des Zertifikatspeichers dar, in dem das Zertifikat gespeichert wird. In diesem Fall verweist er auf den persönlichen Benutzerspeicher.
  • Der Speicherort gibt an, von wo das Zertifikat geladen werden soll (CurrentUser oder LocalMachine).
  • Die name-Eigenschaft des Zertifikats entspricht dem spezifischen Antragsteller des Zertifikats.

Führen Sie zum Bereitstellen in Azure App Service die Schritte unter Bereitstellen der App in Azure aus, in denen erläutert wird, wie Sie die erforderlichen Azure-Ressourcen erstellen und die App in der Produktion bereitstellen.

Nachdem Sie die obigen Anweisungen ausgeführt haben, wird die App in Azure bereitgestellt, sie ist aber noch nicht funktionsfähig. Das von der App verwendete Zertifikat muss im Azure-Portal konfiguriert werden. Suchen Sie den Fingerabdruck für das Zertifikat, und führen Sie die unter Laden Ihrer Zertifikate beschriebenen Schritte aus.

Auch wenn in diesen Schritten SSL angegeben ist, gibt es im Azure-Portal einen Bereich Private Zertifikate, in dem Sie das bereitgestellte Zertifikat für die Verwendung mit der App hochladen können.

Nachdem Sie die App und die Einstellungen der App im Azure-Portal konfiguriert haben, starten Sie die App im Portal neu.

Weitere Konfigurationsoptionen

Die Unterstützung der API-Autorisierung basiert auf IdentityServer mit einigen Konventionen, Standardwerten und Verbesserungen, um die Erfahrung für Single-Page-Webanwendungen (SPAs) zu vereinfachen. Dabei muss nicht erwähnt werden, dass die volle Leistungsfähigkeit von IdentityServer im Hintergrund verfügbar ist, wenn die ASP.NET Core-Integrationen Ihr Szenario nicht abdecken. Die ASP.NET Core-Unterstützung konzentriert sich auf „Erstanbieter“-Apps, bei denen alle Apps von uns erstellt und bereitgestellt werden. Daher wird keine Unterstützung für Aspekte wie Einwilligung oder Verbund angeboten. Verwenden Sie in solchen Szenarien IdentityServer, und befolgen Sie die entsprechende Dokumentation.

Anwendungsprofile

Anwendungsprofile sind vordefinierte Konfigurationen für Apps, die ihre Parameter genauer definieren. Derzeit werden die folgenden Profile unterstützt:

  • IdentityServerSPA stellt eine SPA dar, die zusammen mit IdentityServer als einzelne Einheit gehostet wird.
    • Der Standardwert von redirect_uri lautet /authentication/login-callback.
    • Der Standardwert von post_logout_redirect_uri lautet /authentication/logout-callback.
    • Zu den Bereichen gehören openid, profile und alle Bereiche, die in der App für die APIs definiert sind.
    • Die zulässigen OIDC-Antworttypen sind id_token token oder jeder einzelne Typ (id_token, token).
    • Der zulässige Antwortmodus ist fragment.
  • SPA stellt eine Single-Page-Webanwendung dar, die nicht mit IdentityServer gehostet wird.
    • Zu den Bereichen gehören openid, profile und alle Bereiche, die in der App für die APIs definiert sind.
    • Die zulässigen OIDC-Antworttypen sind id_token token oder jeder einzelne Typ (id_token, token).
    • Der zulässige Antwortmodus ist fragment.
  • IdentityServerJwt stellt eine API dar, die mit IdentityServer gehostet wird.
    • Die App ist so konfiguriert, dass sie über einen einzelnen Bereich verfügt, der standardmäßig auf den App-Namen festgelegt ist.
  • API stellt eine API dar, die nicht zusammen mit IdentityServer gehostet wird.
    • Die App ist so konfiguriert, dass sie über einen einzelnen Bereich verfügt, der standardmäßig auf den App-Namen festgelegt ist.

Konfigurieren über AppSettings

Konfigurieren Sie die Apps über das Konfigurationssystem, indem Sie sie der Liste von Clients oder Resources hinzufügen.

Konfigurieren Sie die Eigenschaften redirect_uri und post_logout_redirect_uri der einzelnen Clients, wie im folgenden Beispiel gezeigt:

"IdentityServer": {
  "Clients": {
    "MySPA": {
      "Profile": "SPA",
      "RedirectUri": "https://www.example.com/authentication/login-callback",
      "LogoutUri": "https://www.example.com/authentication/logout-callback"
    }
  }
}

Beim Konfigurieren von Ressourcen können Sie die Bereiche für eine Ressource wie unten gezeigt konfigurieren:

"IdentityServer": {
  "Resources": {
    "MyExternalApi": {
      "Profile": "API",
      "Scopes": "a b c"
    }
  }
}

Konfigurieren über Code

Sie können die Clients und Ressourcen auch im Code konfigurieren, indem Sie eine Überladung von AddApiAuthorization verwenden, die eine Aktion zum Konfigurieren von Optionen ausführt.

AddApiAuthorization<ApplicationUser, ApplicationDbContext>(options =>
{
    options.Clients.AddSPA(
        "My SPA", spa =>
        spa.WithRedirectUri("http://www.example.com/authentication/login-callback")
           .WithLogoutRedirectUri(
               "http://www.example.com/authentication/logout-callback"));

    options.ApiResources.AddApiResource("MyExternalApi", resource =>
        resource.WithScopes("a", "b", "c"));
});

Zusätzliche Ressourcen

Die Vorlagen von ASP.NET Core 3.1 und höher bieten eine Authentifizierung in Single-Page-Webanwendungen (SPAs) unter Verwendung der Unterstützung für die API-Autorisierung. ASP.NET Core Identity wird für die Authentifizierung und zum Speichern von Benutzer*innen mit IdentityServer für die Implementierung von OpenID Connect kombiniert.

Den Angular- und React-Projektvorlagen wurde ein Authentifizierungsparameter hinzugefügt, der dem Authentifizierungsparameter in den Projektvorlagen für Webanwendung (Model View Controller) (MVC) und Webanwendung (Razor Pages) ähnelt. Die zulässigen Parameterwerte sind None und Individual. Die Projektvorlage für React.js und Redux unterstützt den Authentifizierungsparameter derzeit nicht.

Erstellen einer App mit Unterstützung für die API-Autorisierung

Die Benutzerauthentifizierung und -autorisierung kann sowohl mit Angular- als auch mit React-SPAs verwendet werden. Öffnen Sie eine Befehlsshell, und führen Sie den folgenden Befehl aus:

Angular:

dotnet new angular -o <output_directory_name> 

React:

dotnet new react -o <output_directory_name> -au Individual

Mit dem obigen Befehl wird eine ASP.NET Core-App mit einem ClientApp-Verzeichnis erstellt, das die Single-Page-Webanwendung enthält.

Allgemeine Beschreibung der ASP.NET Core-Komponenten der App

In den folgenden Abschnitten werden Ergänzungen zum Projekt erläutert, wenn die Authentifizierungsunterstützung eingeschlossen wird:

Startup-Klasse

Die folgenden Codebeispiele basieren auf dem NuGet-Paket Microsoft.AspNetCore.ApiAuthorization.IdentityServer. In den Beispielen wird die API-Authentifizierung und -Autorisierung mithilfe der Erweiterungsmethoden AddApiAuthorization und AddIdentityServerJwt konfiguriert. Projekte, die die Projektvorlagen für React- oder Angular-SPAs mit Authentifizierung verwenden, enthalten einen Verweis auf dieses Paket.

Die Startup-Klasse verfügt über die folgenden Ergänzungen:

  • Innerhalb der Startup.ConfigureServices-Methode:

    • Identity mit der Standardbenutzeroberfläche:

      services.AddDbContext<ApplicationDbContext>(options =>
          options.UseSqlite(Configuration.GetConnectionString("DefaultConnection")));
      
      services.AddDefaultIdentity<ApplicationUser>()
          .AddEntityFrameworkStores<ApplicationDbContext>();
      
    • IdentityServer mit einer zusätzlichen AddApiAuthorization-Hilfsmethode, die einige ASP.NET Core-Standardkonventionen zusätzlich zu IdentityServer einrichtet:

      services.AddIdentityServer()
          .AddApiAuthorization<ApplicationUser, ApplicationDbContext>();
      
    • Authentifizierung mit einer zusätzlichen AddIdentityServerJwt-Hilfsmethode, die die App so konfiguriert, dass sie von Identity Server generierte JWT-Token überprüft:

      services.AddAuthentication()
          .AddIdentityServerJwt();
      
  • Innerhalb der Startup.Configure-Methode:

    • Die Authentifizierungsmiddleware, die für die Überprüfung der Anforderungsanmeldeinformationen und für das Festlegen des Benutzers auf den Anforderungskontext verantwortlich ist:

      app.UseAuthentication();
      
    • Die IdentityServer-Middleware, die die OpenID Connect-Endpunkte bereitstellt:

      app.UseIdentityServer();
      

Azure App Service für Linux

Geben Sie für Azure App Service-Bereitstellungen unter Linux den Aussteller explizit in Startup.ConfigureServices an:

services.Configure<JwtBearerOptions>(
    IdentityServerJwtConstants.IdentityServerJwtBearerScheme, 
    options =>
    {
        options.Authority = "{AUTHORITY}";
    });

Im obigen Code ist der Platzhalter {AUTHORITY} die Authority, die bei OpenID Connect-Aufrufen verwendet werden soll.

Beispiel:

options.Authority = "https://contoso-service.azurewebsites.net";

AddApiAuthorization

Diese Hilfsmethode konfiguriert IdentityServer für die Verwendung der unterstützten Konfiguration. IdentityServer ist ein leistungsfähiges und erweiterbares Framework für Überlegungen zum Thema „App-Sicherheit“. Dies erhöht gleichzeitig die Komplexität für die meisten gängigen Szenarien unnötig. Daher werden mehrere Konventionen und Konfigurationsoptionen bereitgestellt, die sich gut als Ausgangspunkt eignen. Wenn sich Ihre Anforderungen an die Authentifizierung ändern, bietet IdentityServer eine Vielzahl leistungsfähiger Funktionen, mit denen Sie die Authentifizierung genau an Ihre Anforderungen anpassen können.

AddIdentityServerJwt

Diese Hilfsprogrammmethode konfiguriert ein Richtlinienschema für die App als Standardauthentifizierungshandler. Die Richtlinie ist so konfiguriert, dass Identity alle an beliebige Unterpfade im Identity-URL-Raum „/Identity“ weitergeleiteten Anforderungen verarbeiten kann. JwtBearerHandler verarbeitet alle anderen Anforderungen. Darüber hinaus registriert diese Methode eine <<ApplicationName>>API-API-Ressource bei IdentityServer mit dem Standardbereich <<ApplicationName>>API und konfiguriert die Middleware für JWT-Bearertoken, um von IdentityServer für die App ausgestellte Token zu überprüfen.

WeatherForecastController

Beachten Sie in der Datei, dass das auf die Klasse angewandte [Authorize]-Attribut angibt, dass die Benutzer*innen basierend auf der Standardrichtlinie autorisiert werden müssen, um auf die Ressource zuzugreifen. Die Standardautorisierungsrichtlinie wird für die Verwendung des Standardauthentifizierungsschemas konfiguriert, das von AddIdentityServerJwt für das oben angegebene Richtlinienschema eingerichtet wurde, sodass der mit einer solchen Hilfsmethode konfigurierte JwtBearerHandler zum Standardhandler für Anforderungen an die App wird.

ApplicationDbContext

Beachten Sie in der Datei, dass derselbe DbContext in Identity verwendet wird, mit der Ausnahme, dass er ApiAuthorizationDbContext erweitert (eine stärker abgeleitete Klasse von IdentityDbContext), um das Schema für IdentityServer einzuschließen.

Für eine vollständige Kontrolle des Datenbankschemas wird von einer der verfügbaren Identity-DbContext-Klassen geerbt, und der Kontext wird so konfiguriert, dass er das Identity-Schema einschließt, indem builder.ConfigurePersistedGrantContext(_operationalStoreOptions.Value) in der OnModelCreating-Methode aufgerufen wird.

OidcConfigurationController

Beachten Sie in der Datei den Endpunkt, der für die Bereitstellung der OIDC-Parameter bereitgestellt wird, die der Client verwenden muss.

appsettings.json

In der Datei appsettings.json im Projektstamm gibt es einen neuen Abschnitt IdentityServer, in dem die Liste der konfigurierten Clients beschrieben wird. Im folgenden Beispiel gibt es einen einzelnen Client. Der Clientname entspricht dem App-Namen, und er wird durch Konventionen dem OAuth-ClientId-Parameter zugeordnet. Das Profil gibt den App-Typ an, der konfiguriert wird. Es wird intern verwendet, um Konventionen zu etablieren, die den Konfigurationsprozess für den Server vereinfachen. Es sind mehrere Profile verfügbar, wie im Abschnitt Anwendungsprofile erläutert.

"IdentityServer": {
  "Clients": {
    "angularindividualpreview3final": {
      "Profile": "IdentityServerSPA"
    }
  }
}

appsettings.Development.json

In der Datei appsettings.Development.json im Projektstamm befindet sich ein Abschnitt IdentityServer, in dem der zum Signieren von Token verwendete Schlüssel beschrieben wird. Bei der Bereitstellung in der Produktion muss ein Schlüssel zusammen mit der App bereitgestellt werden, wie im Abschnitt Bereitstellen in der Produktion erläutert.

"IdentityServer": {
  "Key": {
    "Type": "Development"
  }
}

Allgemeine Beschreibung der Angular-App

Die Unterstützung für Authentifizierung und API-Autorisierung in der Angular-Vorlage befindet sich in einem eigenen Angular-Modul im Verzeichnis ClientApp/src/api-authorization. Das Modul besteht aus folgenden Elementen:

  • 3 Komponenten:
    • login.component.ts verarbeitet den Anmeldeflow der App.
    • logout.component.ts verarbeitet den Abmeldeflow der App.
    • login-menu.component.ts ist ein Widget, das einen der folgenden Linksätze anzeigt:
      • Benutzerprofilverwaltung und Abmeldelinks, wenn Benutzer*innen authentifiziert werden
      • Registrierungs- und Anmeldelinks, wenn Benutzer*innen nicht authentifiziert werden
  • Ein Routenwächter (AuthorizeGuard), der Routen hinzugefügt werden kann und erzwingt, dass Benutzer*innen authentifiziert werden, bevor die Route besucht wird
  • Ein HTTP-Interceptor (AuthorizeInterceptor), der das Zugriffstoken an ausgehende HTTP-Anforderungen an die API anfügt, wenn Benutzer*innen authentifiziert werden
  • Ein Dienst (AuthorizeService), der die Details auf niedrigerer Ebene des Authentifizierungsprozesses verarbeitet und Informationen zu den authentifizierten Benutzer*innen für die übrige App zur Nutzung verfügbar macht
  • Ein Angular-Modul, das Routen definiert, die den Authentifizierungskomponenten der App zugeordnet sind Es werden die Anmeldemenükomponente, der Interceptor, der Wächter und der Dienst für die Nutzung durch die übrige App verfügbar gemacht.

Allgemeine Beschreibung der React-App

Die Unterstützung für die Authentifizierung und API-Autorisierung in der React-Vorlage befindet sich im Verzeichnis ClientApp/src/components/api-authorization. Sie besteht aus folgenden Elementen:

  • 4 Komponenten:
    • Login.js verarbeitet den Anmeldeflow der App.
    • Logout.js verarbeitet den Abmeldeflow der App.
    • LoginMenu.js ist ein Widget, das einen der folgenden Linksätze anzeigt:
      • Benutzerprofilverwaltung und Abmeldelinks, wenn Benutzer*innen authentifiziert werden
      • Registrierungs- und Anmeldelinks, wenn Benutzer*innen nicht authentifiziert werden
    • AuthorizeRoute.js ist eine Routenkomponente, für die Benutzer*innen authentifiziert werden müssen, bevor die im Component-Parameter angegebene Komponente gerendert wird.
  • Eine exportierte authService-Instanz der AuthorizeService-Klasse, die die Details auf niedrigerer Ebene des Authentifizierungsprozesses verarbeitet und Informationen zu den authentifizierten Benutzer*innen für die übrige App zur Nutzung verfügbar macht

Nachdem Sie nun die wichtigsten Komponenten der Lösung kennengelernt haben, können Sie sich die einzelnen Szenarien für die App genauer ansehen.

Erzwingen der Autorisierung für eine neue API

Standardmäßig ist das System so konfiguriert, dass die Autorisierung für neue APIs problemlos erzwungen werden kann. Erstellen Sie dazu einen neuen Controller, und fügen Sie das [Authorize]-Attribut der Controllerklasse oder einer beliebigen Aktion innerhalb des Controllers hinzu.

Anpassen des API-Authentifizierungshandlers

Um die Konfiguration des JWT-Handlers der API anzupassen, konfigurieren Sie dessen JwtBearerOptions-Instanz:

services.AddAuthentication()
    .AddIdentityServerJwt();

services.Configure<JwtBearerOptions>(
    IdentityServerJwtConstants.IdentityServerJwtBearerScheme,
    options =>
    {
        ...
    });

Der JWT-Handler der API löst Ereignisse aus, die das Steuern des Authentifizierungsprozesses mithilfe von JwtBearerEvents ermöglichen. Um Unterstützung für die API-Autorisierung bereitzustellen, registriert AddIdentityServerJwt seine eigenen Ereignishandler.

Um die Behandlung eines Ereignisses anzupassen, umschließen Sie den vorhandenen Ereignishandler nach Bedarf mit zusätzlicher Logik. Beispiel:

services.Configure<JwtBearerOptions>(
    IdentityServerJwtConstants.IdentityServerJwtBearerScheme,
    options =>
    {
        var onTokenValidated = options.Events.OnTokenValidated;       

        options.Events.OnTokenValidated = async context =>
        {
            await onTokenValidated(context);
            ...
        }
    });

Im obigen Code wird der OnTokenValidated-Ereignishandler durch eine benutzerdefinierte Implementierung ersetzt. Diese Implementierung führt Folgendes aus:

  1. Aufrufen der ursprüngliche Implementierung, die von der API-Autorisierungsunterstützung bereitgestellt wird
  2. Ausführen der eigenen benutzerdefinierten Logik

Schützen einer clientseitigen Route (Angular)

Der Schutz einer clientseitigen Route erfolgt durch Hinzufügen des Autorisierungswächters zur Liste der auszuführenden Wächter beim Konfigurieren einer Route. Sehen Sie sich z. B. an, wie die fetch-data-Route innerhalb des Angular-Moduls der Haupt-App konfiguriert wird:

RouterModule.forRoot([
  // ...
  { path: 'fetch-data', component: FetchDataComponent, canActivate: [AuthorizeGuard] },
])

Es ist wichtig zu erwähnen, dass der Schutz einer Route nicht den eigentlichen Endpunkt selbst schützt (auf den immer noch ein [Authorize]-Attribut angewandt werden muss), sondern dass Benutzer*innen lediglich daran gehindert werden, zur angegebenen clientseitigen Route zu navigieren, wenn sie nicht authentifiziert sind.

Authentifizieren von API-Anforderungen (Angular)

Die Authentifizierung von Anforderungen an APIs, die zusammen mit der App gehostet werden, erfolgt automatisch mithilfe des von der App definierten Interceptors des HTTP-Clients.

Schützen einer clientseitigen Route (React)

Sie schützen eine clientseitige Route, indem Sie die AuthorizeRoute-Komponente anstelle der einfachen Route-Komponente verwenden. Beachten Sie beispielsweise, wie die fetch-data-Route innerhalb der App-Komponente konfiguriert ist:

<AuthorizeRoute path='/fetch-data' component={FetchData} />

Schützen einer Route:

  • Der eigentliche Endpunkt wird nicht geschützt (auf ihn muss immer noch ein [Authorize]-Attribut angewandt werden).
  • Es wird nur verhindert, dass Benutzer*innen zur angegebenen clientseitigen Route navigieren, wenn sie nicht authentifiziert sind.

Authentifizieren von API-Anforderungen (React)

Die Authentifizierung von Anforderungen mit React erfolgt, indem zuerst die authService-Instanz aus dem AuthorizeService importiert wird. Das Zugriffstoken wird wie unten dargestellt von authService abgerufen und an die Anforderung angefügt. In React-Komponenten erfolgt dieser Schritt in der Regel in der componentDidMount-Lebenszyklusmethode oder als Ergebnis einer Benutzerinteraktion.

Importieren des authService in eine Komponente

import authService from './api-authorization/AuthorizeService'

Abrufen und Anfügen des Zugriffstokens an die Antwort

async populateWeatherData() {
  const token = await authService.getAccessToken();
  const response = await fetch('api/SampleData/WeatherForecasts', {
    headers: !token ? {} : { 'Authorization': `Bearer ${token}` }
  });
  const data = await response.json();
  this.setState({ forecasts: data, loading: false });
}

Bereitstellen für die Produktion

Um die App in der Produktion bereitzustellen, müssen die folgenden Ressourcen bereitgestellt werden:

  • Eine Datenbank zum Speichern der Identity-Benutzerkonten und der IdentityServer-Zuweisungen
  • Ein Produktionszertifikat zum Signieren von Token.
    • Für dieses Zertifikat gibt es keine spezifischen Anforderungen. Es kann sich um ein selbstsigniertes Zertifikat oder ein Zertifikat handeln, das über eine Zertifizierungsstelle bereitgestellt wird.
    • Es kann mit Standardtools wie PowerShell oder OpenSSL generiert werden.
    • Es kann im Zertifikatspeicher auf den Zielcomputern installiert oder als PFX-Datei mit einem sicheren Kennwort bereitgestellt werden.

Beispiel: Bereitstellen bei einem anderen Webhostinganbieter als Azure

Erstellen Sie Ihr Zertifikat in Ihrem Webhostingbereich, oder laden Sie es. Ändern Sie dann in der Datei appsettings.json der App den Abschnitt IdentityServer, um Schlüsseldetails einzuschließen. Beispiel:

"IdentityServer": {
  "Key": {
    "Type": "Store",
    "StoreName": "WebHosting",
    "StoreLocation": "CurrentUser",
    "Name": "CN=MyApplication"
  }
}

Im vorherigen Beispiel:

  • StoreName stellt den Namen des Zertifikatspeichers dar, in dem das Zertifikat gespeichert wird. In diesem Fall verweist er auf den Webhostingspeicher.
  • StoreLocation gibt an, von wo das Zertifikat geladen werden soll (in diesem Fall CurrentUser).
  • Name entspricht dem spezifischen Antragsteller des Zertifikats.

Beispiel: Bereitstellen in Azure App Service

In diesem Abschnitt wird die Bereitstellung der App für Azure App Service mithilfe eines im Zertifikatspeicher gespeicherten Zertifikats beschrieben. Um die App so zu ändern, dass sie ein Zertifikat aus dem Zertifikatspeicher lädt, ist ein Dienstplan im Tarif Standard oder höher erforderlich, wenn Sie die App in einem späteren Schritt im Azure-Portal konfigurieren.

Ändern Sie in der Datei appsettings.json der App den Abschnitt IdentityServer, um Schlüsseldetails einzuschließen:

"IdentityServer": {
  "Key": {
    "Type": "Store",
    "StoreName": "My",
    "StoreLocation": "CurrentUser",
    "Name": "CN=MyApplication"
  }
}
  • Der Speichername stellt den Namen des Zertifikatspeichers dar, in dem das Zertifikat gespeichert wird. In diesem Fall verweist er auf den persönlichen Benutzerspeicher.
  • Der Speicherort gibt an, von wo das Zertifikat geladen werden soll (CurrentUser oder LocalMachine).
  • Die name-Eigenschaft des Zertifikats entspricht dem spezifischen Antragsteller des Zertifikats.

Führen Sie zum Bereitstellen in Azure App Service die Schritte unter Bereitstellen der App in Azure aus, in denen erläutert wird, wie Sie die erforderlichen Azure-Ressourcen erstellen und die App in der Produktion bereitstellen.

Nachdem Sie die obigen Anweisungen ausgeführt haben, wird die App in Azure bereitgestellt, sie ist aber noch nicht funktionsfähig. Das von der App verwendete Zertifikat muss im Azure-Portal konfiguriert werden. Suchen Sie den Fingerabdruck für das Zertifikat, und führen Sie die unter Laden Ihrer Zertifikate beschriebenen Schritte aus.

Auch wenn in diesen Schritten SSL angegeben ist, gibt es im Azure-Portal einen Bereich Private Zertifikate, in dem Sie das bereitgestellte Zertifikat für die Verwendung mit der App hochladen können.

Nachdem Sie die App und die Einstellungen der App im Azure-Portal konfiguriert haben, starten Sie die App im Portal neu.

Weitere Konfigurationsoptionen

Die Unterstützung der API-Autorisierung basiert auf IdentityServer mit einigen Konventionen, Standardwerten und Verbesserungen, um die Erfahrung für Single-Page-Webanwendungen (SPAs) zu vereinfachen. Dabei muss nicht erwähnt werden, dass die volle Leistungsfähigkeit von IdentityServer im Hintergrund verfügbar ist, wenn die ASP.NET Core-Integrationen Ihr Szenario nicht abdecken. Die ASP.NET Core-Unterstützung konzentriert sich auf „Erstanbieter“-Apps, bei denen alle Apps von uns erstellt und bereitgestellt werden. Daher wird keine Unterstützung für Aspekte wie Einwilligung oder Verbund angeboten. Verwenden Sie in solchen Szenarien IdentityServer, und befolgen Sie die entsprechende Dokumentation.

Anwendungsprofile

Anwendungsprofile sind vordefinierte Konfigurationen für Apps, die ihre Parameter genauer definieren. Derzeit werden die folgenden Profile unterstützt:

  • IdentityServerSPA stellt eine SPA dar, die zusammen mit IdentityServer als einzelne Einheit gehostet wird.
    • Der Standardwert von redirect_uri lautet /authentication/login-callback.
    • Der Standardwert von post_logout_redirect_uri lautet /authentication/logout-callback.
    • Zu den Bereichen gehören openid, profile und alle Bereiche, die in der App für die APIs definiert sind.
    • Die zulässigen OIDC-Antworttypen sind id_token token oder jeder einzelne Typ (id_token, token).
    • Der zulässige Antwortmodus ist fragment.
  • SPA stellt eine Single-Page-Webanwendung dar, die nicht mit IdentityServer gehostet wird.
    • Zu den Bereichen gehören openid, profile und alle Bereiche, die in der App für die APIs definiert sind.
    • Die zulässigen OIDC-Antworttypen sind id_token token oder jeder einzelne Typ (id_token, token).
    • Der zulässige Antwortmodus ist fragment.
  • IdentityServerJwt stellt eine API dar, die mit IdentityServer gehostet wird.
    • Die App ist so konfiguriert, dass sie über einen einzelnen Bereich verfügt, der standardmäßig auf den App-Namen festgelegt ist.
  • API stellt eine API dar, die nicht zusammen mit IdentityServer gehostet wird.
    • Die App ist so konfiguriert, dass sie über einen einzelnen Bereich verfügt, der standardmäßig auf den App-Namen festgelegt ist.

Konfigurieren über AppSettings

Konfigurieren Sie die Apps über das Konfigurationssystem, indem Sie sie der Liste von Clients oder Resources hinzufügen.

Konfigurieren Sie die Eigenschaften redirect_uri und post_logout_redirect_uri der einzelnen Clients, wie im folgenden Beispiel gezeigt:

"IdentityServer": {
  "Clients": {
    "MySPA": {
      "Profile": "SPA",
      "RedirectUri": "https://www.example.com/authentication/login-callback",
      "LogoutUri": "https://www.example.com/authentication/logout-callback"
    }
  }
}

Beim Konfigurieren von Ressourcen können Sie die Bereiche für eine Ressource wie unten gezeigt konfigurieren:

"IdentityServer": {
  "Resources": {
    "MyExternalApi": {
      "Profile": "API",
      "Scopes": "a b c"
    }
  }
}

Konfigurieren über Code

Sie können die Clients und Ressourcen auch im Code konfigurieren, indem Sie eine Überladung von AddApiAuthorization verwenden, die eine Aktion zum Konfigurieren von Optionen ausführt.

AddApiAuthorization<ApplicationUser, ApplicationDbContext>(options =>
{
    options.Clients.AddSPA(
        "My SPA", spa =>
        spa.WithRedirectUri("http://www.example.com/authentication/login-callback")
           .WithLogoutRedirectUri(
               "http://www.example.com/authentication/logout-callback"));

    options.ApiResources.AddApiResource("MyExternalApi", resource =>
        resource.WithScopes("a", "b", "c"));
});

Zusätzliche Ressourcen