Zum Hauptinhalt springen

Schütze deine ASP.NET Core API mit rollenbasierter Zugangskontrolle (RBAC) und JWT-Validierung

Diese Anleitung hilft dir, Autorisierung zu implementieren, um deine ASP.NET Core APIs mit rollenbasierter Zugangskontrolle (RBAC) und JSON Web Tokens (JWTs), die von Logto ausgestellt werden, abzusichern.

Bevor du beginnst

Deine Client-Anwendungen müssen Zugangstokens (Access tokens) von Logto erhalten. Falls du die Client-Integration noch nicht eingerichtet hast, schaue dir unsere Schnellstarts für React, Vue, Angular oder andere Client-Frameworks an oder sieh dir unseren Maschine-zu-Maschine-Leitfaden für Server-zu-Server-Zugriff an.

Dieser Leitfaden konzentriert sich auf die serverseitige Validierung dieser Tokens in deiner ASP.NET Core-Anwendung.

Eine Abbildung, die den Fokus dieses Leitfadens zeigt

Was du lernen wirst

  • JWT-Validierung: Lerne, Zugangstokens (Access tokens) zu validieren und Authentifizierungsinformationen zu extrahieren
  • Middleware-Implementierung: Erstelle wiederverwendbare Middleware zum Schutz deiner API
  • Berechtigungsmodelle: Verstehe und implementiere verschiedene Autorisierungsmuster (Authorization patterns):
    • Globale API-Ressourcen für anwendungsweite Endpunkte
    • Organisationsberechtigungen für mandantenspezifische Funktionskontrolle
    • Organisationsbezogene API-Ressourcen für Multi-Tenant-Datenzugriff
  • RBAC-Integration: Erzwinge rollenbasierte Berechtigungen (Role-based permissions) und Berechtigungen (Scopes) in deinen API-Endpunkten

Voraussetzungen

  • Neueste stabile Version von .NET installiert
  • Grundlegendes Verständnis von ASP.NET Core und Web-API-Entwicklung
  • Eine konfigurierte Logto-Anwendung (siehe Schnellstarts, falls benötigt)

Überblick über Berechtigungsmodelle

Bevor du Schutzmechanismen implementierst, wähle das Berechtigungsmodell, das zu deiner Anwendungsarchitektur passt. Dies steht im Einklang mit den drei Haupt-Autorisierungsszenarien von Logto:

Globale API-Ressourcen RBAC
  • Anwendungsfall: Schutz von API-Ressourcen, die in deiner gesamten Anwendung geteilt werden (nicht organisationsspezifisch)
  • Token-Typ: Zugangstoken (Access token) mit globaler Zielgruppe (Audience)
  • Beispiele: Öffentliche APIs, Kernproduktdienste, Admin-Endpunkte
  • Am besten geeignet für: SaaS-Produkte mit APIs, die von allen Kunden genutzt werden, Microservices ohne Mandantenisolation
  • Mehr erfahren: Globale API-Ressourcen schützen

💡 Wähle dein Modell, bevor du fortfährst – die Umsetzung in diesem Leitfaden bezieht sich durchgehend auf deinen gewählten Ansatz.

Schnelle Vorbereitungsschritte

Logto-Ressourcen & Berechtigungen konfigurieren

  1. API-Ressource erstellen: Gehe zu Konsole → API-Ressourcen und registriere deine API (z. B. https://api.yourapp.com)
  2. Berechtigungen definieren: Füge Berechtigungen wie read:products, write:orders hinzu – siehe API-Ressourcen mit Berechtigungen definieren
  3. Globale Rollen erstellen: Gehe zu Konsole → Rollen und erstelle Rollen, die deine API-Berechtigungen enthalten – siehe Globale Rollen konfigurieren
  4. Rollen zuweisen: Weisen Sie Benutzern oder M2M-Anwendungen, die API-Zugriff benötigen, Rollen zu
Neu bei RBAC?:

Beginne mit unserem Leitfaden zur rollenbasierten Zugangskontrolle (RBAC) für eine Schritt-für-Schritt-Anleitung.

Aktualisiere deine Client-Anwendung

Fordere die passenden Berechtigungen in deinem Client an:

Der Prozess beinhaltet in der Regel die Aktualisierung deiner Client-Konfiguration, um eines oder mehrere der folgenden Elemente einzuschließen:

  • scope-Parameter in OAuth-Flows
  • resource-Parameter für den Zugriff auf API-Ressourcen
  • organization_id für den Organisationskontext
Bevor du mit dem Code beginnst:

Stelle sicher, dass der Benutzer oder die M2M-App, die du testest, die entsprechenden Rollen oder Organisationsrollen zugewiesen bekommen hat, die die notwendigen Berechtigungen für deine API enthalten.

Initialisiere dein API-Projekt

Um ein neues .NET Web API-Projekt zu initialisieren, kannst du die .NET CLI verwenden:

dotnet new webapi -n YourApiName
cd YourApiName

Füge das erforderliche NuGet-Paket für JWT-Authentifizierung hinzu:

dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer

Erstelle einen einfachen API-Controller:

Controllers/ApiController.cs
using Microsoft.AspNetCore.Mvc;

namespace YourApiName.Controllers
{
[ApiController]
[Route("api/[controller]")]
public class ApiController : ControllerBase
{
[HttpGet]
public IActionResult Get()
{
return Ok(new { message = "Hello from .NET API" });
}
}
}

Starte den Entwicklungsserver:

dotnet run
hinweis:

Weitere Informationen zum Einrichten von Controllern, Middleware und anderen Funktionen findest du in der ASP.NET Core-Dokumentation.

Initialisiere Konstanten und Hilfsfunktionen

Definiere die notwendigen Konstanten und Hilfsfunktionen in deinem Code, um die Extraktion und Validierung von Tokens zu handhaben. Eine gültige Anfrage muss einen Authorization-Header in der Form Bearer <Zugangstoken (Access token)> enthalten.

AuthConstants.cs
namespace YourApiNamespace
{
public static class AuthConstants
{
public const string Issuer = "https://your-tenant.logto.app/oidc";
}
}
AuthenticationExceptions.cs
namespace YourApiNamespace.Exceptions
{
public class AuthorizationException : Exception
{
public int StatusCode { get; }

public AuthorizationException(string message, int statusCode = 403) : base(message)
{
StatusCode = statusCode;
}
}
}

Informationen über deinen Logto-Mandanten abrufen

Du benötigst die folgenden Werte, um von Logto ausgestellte Tokens zu validieren:

  • JSON Web Key Set (JWKS) URI: Die URL zu den öffentlichen Schlüsseln von Logto, die zur Überprüfung von JWT-Signaturen verwendet wird.
  • Aussteller (Issuer): Der erwartete Ausstellerwert (die OIDC-URL von Logto).

Zuerst finde den Endpunkt deines Logto-Tenants. Du findest ihn an verschiedenen Stellen:

  • In der Logto-Konsole unter EinstellungenDomains.
  • In den Anwendungseinstellungen, die du in Logto konfiguriert hast, unter EinstellungenEndpoints & Credentials.

Abrufen vom OpenID Connect Discovery-Endpunkt

Diese Werte können vom OpenID Connect Discovery-Endpunkt von Logto abgerufen werden:

https://<your-logto-endpoint>/oidc/.well-known/openid-configuration

Hier ist ein Beispiel für eine Antwort (andere Felder wurden zur Übersichtlichkeit weggelassen):

{
"jwks_uri": "https://your-tenant.logto.app/oidc/jwks",
"issuer": "https://your-tenant.logto.app/oidc"
}

Da Logto keine Anpassung der JWKS-URI oder des Ausstellers (Issuer) erlaubt, kannst du diese Werte fest in deinem Code hinterlegen. Dies wird jedoch für Produktionsanwendungen nicht empfohlen, da dies den Wartungsaufwand erhöhen kann, falls sich zukünftig Konfigurationen ändern.

  • JWKS URI: https://<your-logto-endpoint>/oidc/jwks
  • Aussteller (Issuer): https://<your-logto-endpoint>/oidc

Token und Berechtigungen validieren

Nach dem Extrahieren des Tokens und dem Abrufen der OIDC-Konfiguration überprüfe Folgendes:

  • Signatur: JWT muss gültig und von Logto (über JWKS) signiert sein.
  • Aussteller (Issuer): Muss mit dem Aussteller deines Logto-Tenants übereinstimmen.
  • Zielgruppe (Audience): Muss mit dem in Logto registrierten Ressourcenindikator der API oder dem Organisationskontext (falls zutreffend) übereinstimmen.
  • Ablauf (Expiration): Token darf nicht abgelaufen sein.
  • Berechtigungen (Scopes): Token muss die erforderlichen Berechtigungen für deine API / Aktion enthalten. Berechtigungen sind durch Leerzeichen getrennte Zeichenfolgen im scope-Anspruch.
  • Organisationskontext: Wenn du API-Ressourcen auf Organisationsebene schützt, überprüfe den organization_id-Anspruch.

Siehe JSON Web Token, um mehr über die Struktur und Ansprüche von JWT zu erfahren.

Was bei jedem Berechtigungsmodell zu prüfen ist

  • Audience-Anspruch (aud): API-Ressourcenindikator
  • Organisations-Anspruch (organization_id): Nicht vorhanden
  • Zu prüfende Berechtigungen (scope): API-Ressourcen-Berechtigungen

Für nicht-API-Organisationsberechtigungen wird der Organisationskontext durch den aud-Anspruch dargestellt (z. B. urn:logto:organization:abc123). Der organization_id-Anspruch ist nur für Tokens von API-Ressourcen auf Organisationsebene vorhanden.

tipp:

Validiere immer sowohl Berechtigungen (Scopes) als auch Kontext (Audience, Organisation) für sichere Multi-Tenant-APIs.

Validierungslogik hinzufügen

Füge das erforderliche NuGet-Paket für JWT-Authentifizierung hinzu:

<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.0" />

Erstelle einen Validierungsdienst, um die Tokenvalidierung zu übernehmen:

JwtValidationService.cs
using System.Security.Claims;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using YourApiNamespace.Exceptions;

namespace YourApiNamespace.Services
{
public interface IJwtValidationService
{
Task ValidateTokenAsync(TokenValidatedContext context);
}

public class JwtValidationService : IJwtValidationService
{
public async Task ValidateTokenAsync(TokenValidatedContext context)
{
var principal = context.Principal!;

try
{
// Füge hier deine Validierungslogik basierend auf dem Berechtigungsmodell ein
ValidatePayload(principal);
}
catch (AuthorizationException)
{
throw; // Autorisierungsfehler erneut auslösen
}
catch (Exception ex)
{
throw new AuthorizationException($"Tokenvalidierung fehlgeschlagen: {ex.Message}", 401);
}
}

private void ValidatePayload(ClaimsPrincipal principal)
{
// Implementiere hier deine Überprüfungslogik basierend auf dem Berechtigungsmodell
// Dies wird im Abschnitt zu den Berechtigungsmodellen unten gezeigt
}
}
}

Konfiguriere die JWT-Authentifizierung in deiner Program.cs:

Program.cs
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using YourApiNamespace.Services;
using YourApiNamespace.Exceptions;

var builder = WebApplication.CreateBuilder(args);

// Füge Dienste zum Container hinzu
builder.Services.AddControllers();
builder.Services.AddScoped<IJwtValidationService, JwtValidationService>();

// Konfiguriere JWT-Authentifizierung
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.Authority = AuthConstants.Issuer;
options.MetadataAddress = $"{AuthConstants.Issuer}/.well-known/openid_configuration";
options.RequireHttpsMetadata = true;
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidIssuer = AuthConstants.Issuer,
ValidateAudience = false, // Die Zielgruppe wird manuell basierend auf dem Berechtigungsmodell validiert
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ClockSkew = TimeSpan.FromMinutes(5)
};

options.Events = new JwtBearerEvents
{
OnTokenValidated = async context =>
{
var validationService = context.HttpContext.RequestServices
.GetRequiredService<IJwtValidationService>();

await validationService.ValidateTokenAsync(context);
},
OnAuthenticationFailed = context =>
{
// Behandle JWT-Bibliotheksfehler als 401
context.Response.StatusCode = 401;
context.Response.ContentType = "application/json";
context.Response.WriteAsync($"{{\"error\": \"Invalid token\"}}");
context.HandleResponse();
return Task.CompletedTask;
}
};
});

builder.Services.AddAuthorization();

var app = builder.Build();

// Globale Fehlerbehandlung für Authentifizierungs- / Autorisierungsfehler
app.Use(async (context, next) =>
{
try
{
await next();
}
catch (AuthorizationException ex)
{
context.Response.StatusCode = ex.StatusCode;
context.Response.ContentType = "application/json";
await context.Response.WriteAsync($"{{\"error\": \"{ex.Message}\"}}");
}
});

// Konfiguriere die HTTP-Request-Pipeline
app.UseAuthentication();
app.UseAuthorization();

app.MapControllers();

app.Run();

Implementiere entsprechend deinem Berechtigungsmodell die passende Validierungslogik in JwtValidationService:

JwtValidationService.cs
private void ValidatePayload(ClaimsPrincipal principal)
{
// Überprüfe, ob der Audience-Claim mit deinem API-Ressourcenindikator übereinstimmt
var audiences = principal.FindAll("aud").Select(c => c.Value).ToList();
if (!audiences.Contains("https://your-api-resource-indicator"))
{
throw new AuthorizationException("Ungültige Zielgruppe (audience)");
}

// Überprüfe erforderliche Berechtigungen für globale API-Ressourcen
var requiredScopes = new[] { "api:read", "api:write" }; // Ersetze durch deine tatsächlichen erforderlichen Berechtigungen
var tokenScopes = principal.FindFirst("scope")?.Value?.Split(' ') ?? Array.Empty<string>();

if (!requiredScopes.All(scope => tokenScopes.Contains(scope)))
{
throw new AuthorizationException("Unzureichende Berechtigung (scope)");
}
}

Middleware auf deine API anwenden

Wende nun die Middleware auf deine geschützten API-Routen an.

Wir haben bereits die Authentifizierungs- und Autorisierungsmiddleware in den vorherigen Abschnitten eingerichtet. Jetzt können wir einen geschützten Controller erstellen, der Zugangstokens validiert und Ansprüche (Claims) aus authentifizierten Anfragen extrahiert.

ProtectedController.cs
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System.Security.Claims;

namespace YourApiNamespace.Controllers
{
[ApiController]
[Route("api/[controller]")]
[Authorize] // Authentifizierung für alle Aktionen in diesem Controller erforderlich
public class ProtectedController : ControllerBase
{
[HttpGet]
public IActionResult GetProtectedData()
{
// Informationen aus dem Zugangstoken direkt aus den User-Ansprüchen (Claims) abrufen
var sub = User.FindFirst(ClaimTypes.NameIdentifier)?.Value ?? User.FindFirst("sub")?.Value;
var clientId = User.FindFirst("client_id")?.Value;
var organizationId = User.FindFirst("organization_id")?.Value;
var scopes = User.FindFirst("scope")?.Value?.Split(' ') ?? Array.Empty<string>();
var audience = User.FindAll("aud").Select(c => c.Value).ToArray();

return Ok(new {
sub,
client_id = clientId,
organization_id = organizationId,
scopes,
audience
});
}

[HttpGet("claims")]
public IActionResult GetAllClaims()
{
// Gibt alle Ansprüche (Claims) zur Fehleranalyse / Überprüfung zurück
var claims = User.Claims.Select(c => new { c.Type, c.Value }).ToList();
return Ok(new { claims });
}
}
}

Teste deine geschützte API

Zugangstokens erhalten

Von deiner Client-Anwendung: Wenn du eine Client-Integration eingerichtet hast, kann deine App Tokens automatisch erhalten. Extrahiere das Zugangstoken und verwende es in API-Anfragen.

Zum Testen mit curl / Postman:

  1. Benutzertokens: Verwende die Entwicklertools deiner Client-App, um das Zugangstoken aus dem localStorage oder dem Netzwerk-Tab zu kopieren.

  2. Maschine-zu-Maschine-Tokens: Verwende den Client-Credentials-Flow. Hier ein nicht-normatives Beispiel mit curl:

    curl -X POST https://your-tenant.logto.app/oidc/token \
    -H "Content-Type: application/x-www-form-urlencoded" \
    -d "grant_type=client_credentials" \
    -d "client_id=your-m2m-client-id" \
    -d "client_secret=your-m2m-client-secret" \
    -d "resource=https://your-api-resource-indicator" \
    -d "scope=api:read api:write"

    Möglicherweise musst du die Parameter resource und scope entsprechend deiner API-Ressource und Berechtigungen anpassen; ein organization_id-Parameter kann ebenfalls erforderlich sein, wenn deine API organisationsgebunden ist.

tipp:

Möchtest du den Inhalt des Tokens inspizieren? Verwende unseren JWT Decoder, um deine JWTs zu dekodieren und zu überprüfen.

Geschützte Endpunkte testen

Gültige Token-Anfrage
curl -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..." \
http://localhost:3000/api/protected

Erwartete Antwort:

{
"auth": {
"sub": "user123",
"clientId": "app456",
"organizationId": "org789",
"scopes": ["api:read", "api:write"],
"audience": ["https://your-api-resource-indicator"]
}
}
Fehlendes Token
curl http://localhost:3000/api/protected

Erwartete Antwort (401):

{
"error": "Authorization header is missing"
}
Ungültiges Token
curl -H "Authorization: Bearer invalid-token" \
http://localhost:3000/api/protected

Erwartete Antwort (401):

{
"error": "Invalid token"
}

Berechtigungsmodell-spezifisches Testen

Testszenarien für APIs, die mit globalen Berechtigungen geschützt sind:

  • Gültige Berechtigungen: Teste mit Tokens, die deine erforderlichen API-Berechtigungen enthalten (z. B. api:read, api:write)
  • Fehlende Berechtigungen: Erwarte 403 Verboten, wenn das Token die erforderlichen Berechtigungen nicht enthält
  • Falsche Zielgruppe: Erwarte 403 Verboten, wenn die Zielgruppe nicht mit der API-Ressource übereinstimmt
# Token mit fehlenden Berechtigungen - erwarte 403
curl -H "Authorization: Bearer token-without-required-scopes" \
http://localhost:3000/api/protected

Weiterführende Literatur

RBAC in der Praxis: Sichere Autorisierung für deine Anwendung implementieren

Entwicklung einer Multi-Tenant-SaaS-Anwendung: Ein vollständiger Leitfaden von Design bis Implementierung