Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
In diesem Artikel wird beschrieben, wie Sie Benutzer für den Zugriff auf App-Ressourcen autorisieren.
In einer App wird eine Ressource in der Regel durch eine C#-Klasse dargestellt, die daten enthält, die in einer Sammlung gespeichert sind, z. B. ein byte[] Array. Die Klasse enthält in der Regel zusätzliche Metadaten, die sich auf die Ressource beziehen, z. B. einen eindeutigen Ressourcenbezeichner, Datumsangaben, Autoren, Quellinformationen und einen Anzeigenamen für die Anzeige in einer Benutzeroberfläche. Die Sammlung, die Ressourcendaten enthält, wird in der Regel aus physischen Dateiinhalten, einem Cloudspeicherobjekt, einem Speicherobjekt oder Daten aus einer Datenbank geladen.
Die ressourcenbasierte Autorisierung erfordert besondere Aufmerksamkeit in ASP.NET Core Apps. Die Attributauswertung erfolgt vor der Datenbindung und vor der Ausführung einer Methode, die eine Ressource lädt. Die deklarative Autorisierung mit einem [Authorize] Attribut reicht nicht für die ressourcenbasierte Autorisierung aus. Stattdessen muss die App eine benutzerdefinierte Autorisierungsmethode aufrufen – ein Ansatz, der als imperative Autorisierung bezeichnet wird.
In diesem Artikel werden Razor Komponentenbeispiele verwendet und sich auf Blazor Autorisierungsszenarien für ASP.NET Core 3.1 oder höher konzentriert. Informationen zu Razor Pages und MVC-Anleitungen, die für alle Versionen von ASP.NET Core gelten, finden Sie in den folgenden Ressourcen:
- Ressourcebasierte Autorisierung in ASP.NET Core Razor Pages
- Ressourcebasierte Autorisierung in ASP.NET Core MVC
Beispiele in diesem Artikel verwenden primäre Konstruktoren, die in C# 12 (.NET 8) oder höher verfügbar sind. Weitere Informationen finden Sie unter Declare primary constructors for classes and structs (C# documentation tutorial) und Primary constructors (C# Guide).
Beispiel-App
Das Blazor Web App Beispiel für diesen Artikel ist die BlazorWebAppAuthorization Beispiel-App (dotnet/AspNetCore.Docs.Samples GitHub-Repository) (herunterladen). Die Beispiel-App verwendet Seeded-Konten mit vorkonfigurierten Dokumentobjekten, um die Beispiele in diesem Artikel zu veranschaulichen. Weitere Informationen finden Sie in der README-Datei des Beispiels (README.md).
Vorsicht
Diese Beispiel-App verwendet eine Speicherdatenbank, um Benutzerinformationen zu speichern, die für Produktionsszenarien nicht geeignet sind. Die Beispiel-App dient nur zu Demonstrationszwecken und sollte nicht als Ausgangspunkt für Produktions-Apps verwendet werden.
Verwenden der imperativen Autorisierung
Die Autorisierung wird als IAuthorizationService implementiert, das beim Start der App durch das ASP.NET Core-Framework in der Dienstesammlung registriert wird. Der Dienst wird komponenten Razor und anderen Klassen über abhängigkeitsinjektion zur Verfügung gestellt:
@using Microsoft.AspNetCore.Authorization
@inject IAuthorizationService AuthorizationService
IAuthorizationService verfügt über zwei AuthorizeAsync Methodenüberladungen. Eine der Überladungen akzeptiert einen Ressourcen- und Richtliniennamen:
Task<AuthorizationResult> AuthorizeAsync(
ClaimsPrincipal user,
object resource,
string policyName);
Die andere Überladung akzeptiert eine Ressource und eine Sammlung von Anforderungen (IAuthorizationRequirement), die ausgewertet werden sollen:
Task<AuthorizationResult> AuthorizeAsync(
ClaimsPrincipal user,
object resource,
IEnumerable<IAuthorizationRequirement> requirements);
Im folgenden Beispiel, das vollständig im Abschnitt "Erstellen eines ressourcenbasierten Handlers " erläutert wird, wird die gesicherte Ressource in ein benutzerdefiniertes Document Objekt geladen. Eine AuthorizeAsync Überladung wird aufgerufen, um zu bestimmen, ob der aktuelle Benutzer auf das Dokument basierend auf der Autorisierungsrichtlinie "SameAuthorPolicy" zugreifen darf. Wenn authorizationResult.Succeededtrue ist, ist der Benutzer für das Dokument berechtigt, weil er das Dokument verfasst hat (Document.Author stimmt mit dem Name des Benutzers überein):
protected override async Task OnParametersSetAsync()
{
var user = (await AuthStateProvider.GetAuthenticationStateAsync()).User;
if (user.Identity is not null && user.Identity.IsAuthenticated)
{
var document = DocumentRepository.Find(DocumentId);
...
var authorizationResult = await AuthorizationService
.AuthorizeAsync(user, document, "SameAuthorPolicy");
...
}
}
Erstellen eines ressourcenbasierten Handlers
Das Erstellen eines ressourcenbasierten Autorisierungshandlers ähnelt dem Erstellen eines einfachen Anforderungshandlers. Erstellen Sie eine benutzerdefinierte Anforderungsklasse, und implementieren Sie eine Anforderungshandlerklasse. Weitere Informationen zum Erstellen einer Anforderungsklasse finden Sie unter Richtlinienbasierte Autorisierung: Anforderungen.
Die folgende Demonstrationsklasse Document wird verwendet:
namespace BlazorWebAppAuthorization.Models;
public class Document
{
public string? Author { get; set; }
public byte[]? Content { get; set; }
public Guid ID { get; set; }
public string? Title { get; set; }
}
Die Handlerklasse gibt die Anforderung und den Ressourcentyp an. Im folgenden Beispiel wird ein Handler veranschaulicht, der eine SameAuthorRequirement Anforderung und eine Document Ressource verwendet.
Services/DocumentAuthorizationHandler.cs:
using Microsoft.AspNetCore.Authorization;
using BlazorWebAppAuthorization.Models;
namespace BlazorWebAppAuthorization.Services;
public class DocumentAuthorizationHandler :
AuthorizationHandler<SameAuthorRequirement, Document>
{
protected override Task HandleRequirementAsync(
AuthorizationHandlerContext context,
SameAuthorRequirement requirement,
Document resource)
{
if (context.User.Identity?.Name == resource.Author)
{
context.Succeed(requirement);
}
return Task.CompletedTask;
}
}
public class SameAuthorRequirement : IAuthorizationRequirement { }
Registrieren Sie die Anforderung und den Handler in Program.cs:
builder.Services.AddAuthorizationBuilder()
.AddPolicy("SameAuthorPolicy", policy =>
policy.Requirements.Add(new SameAuthorRequirement()));
builder.Services.AddSingleton<IAuthorizationHandler, DocumentAuthorizationHandler>();
Registrieren Sie die Anforderung und den Handler in Startup.ConfigureServices:
services.AddAuthorization(options =>
{
options.AddPolicy("SameAuthorPolicy", policy =>
policy.Requirements.Add(new SameAuthorRequirement()));
});
services.AddSingleton<IAuthorizationHandler, DocumentAuthorizationHandler>();
Weitere Informationen zum Erstellen von Autorisierungsrichtlinien finden Sie unter Policy-basierte Autorisierung in ASP.NET Core.
Die folgende AccessDocument Komponente ruft eine AuthorizeAsync Überladung auf, um festzustellen, ob der aktuelle Benutzer ein Dokument basierend auf der Autorisierungsrichtlinie "SameAuthorPolicy" anzeigen darf. Wenn authorizationResult.Succeededtrue wahr ist, ist der Benutzer zum Zugriff auf das Dokument berechtigt, weil er das Dokument verfasst hat (Document.Author entspricht der Name des Benutzers).
Pages/AccessDocument.razor:
@page "/access-document/{documentId}"
@using Microsoft.AspNetCore.Authorization
@using BlazorWebAppAuthorization.Data
@inject AuthenticationStateProvider AuthStateProvider
@inject IAuthorizationService AuthorizationService
@inject IDocumentRepository DocumentRepository
<h1>Access Document</h1>
<AuthorizeView>
<Authorized>
<p>Hello, @context.User.Identity?.Name!</p>
<p>@message</p>
</Authorized>
<NotAuthorized>
<p>You're not authorized to access this page.</p>
</NotAuthorized>
</AuthorizeView>
@code {
private string? message;
[Parameter]
public string? DocumentId { get; set; }
protected override async Task OnParametersSetAsync()
{
var user = (await AuthStateProvider.GetAuthenticationStateAsync()).User;
if (user.Identity is not null && user.Identity.IsAuthenticated)
{
var document = DocumentRepository.Find(DocumentId);
if (document == null)
{
message = "Document not found.";
return;
}
var authorizationResult = await AuthorizationService
.AuthorizeAsync(user, document, "SameAuthorPolicy");
message = authorizationResult.Succeeded
? $"You are authorized for document {DocumentId}."
: $"You are NOT authorized for document {DocumentId}.";
}
}
}
In der Beispiel-App ist jeder App-Benutzer berechtigt, auf das vordefinierte Dokument zuzugreifen, das er verfasst hat.
Betriebliche Anforderungen
Um Entscheidungen basierend auf den Ergebnissen von CRUD-Vorgängen (Create, Read, Update, Delete) zu treffen, verwenden Sie die OperationAuthorizationRequirement Hilfsklasse. Mit der Hilfsklasse können Sie einen einzelnen Handler anstelle einer einzelnen Klasse für jeden Vorgangstyp schreiben. Die folgende Operations Klasse richtet alle vier CRUD-Vorgangstypen ein:
using Microsoft.AspNetCore.Authorization.Infrastructure;
public static class Operations
{
public static readonly OperationAuthorizationRequirement Create =
new() { Name = nameof(Create) };
public static readonly OperationAuthorizationRequirement Delete =
new() { Name = nameof(Delete) };
public static readonly OperationAuthorizationRequirement Read =
new() { Name = nameof(Read) };
public static readonly OperationAuthorizationRequirement Update =
new() { Name = nameof(Update) };
}
Der folgende DocumentAuthorizationCrudHandler Autorisierungshandler überprüft den Vorgang mithilfe der Ressource, der Identität (Rolle) des Benutzers in einigen Fällen und der Eigenschaft der Name Anforderung:
- Alle Benutzer können Dokumente lesen.
- Nur Benutzer in der
AdminRolle können Dokumente erstellen und aktualisieren. - Nur Benutzer in der
SuperUserRolle können Dokumente löschen.
Services/DocumentAuthorizationCrudHandler.cs:
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Authorization.Infrastructure;
using BlazorWebAppAuthorization.Models;
namespace BlazorWebAppAuthorization.Services;
public class DocumentAuthorizationCrudHandler :
AuthorizationHandler<OperationAuthorizationRequirement, Document>
{
protected override Task HandleRequirementAsync(
AuthorizationHandlerContext context,
OperationAuthorizationRequirement requirement,
Document resource)
{
if (requirement.Name == Operations.Create.Name &&
context.User.IsInRole("Admin"))
{
context.Succeed(requirement);
}
if (requirement.Name == Operations.Delete.Name &&
context.User.IsInRole("SuperUser"))
{
context.Succeed(requirement);
}
if (requirement.Name == Operations.Read.Name)
{
context.Succeed(requirement);
}
if (requirement.Name == Operations.Update.Name &&
context.User.IsInRole("Admin"))
{
context.Succeed(requirement);
}
return Task.CompletedTask;
}
}
Wo Dienste in der App registriert sind:
builder.Services.AddSingleton<IAuthorizationHandler, DocumentAuthorizationCrudHandler>();
Rufen Sie die Überladung von AuthorizeAsync mit dem Vorgang auf, um das Autorisierungsergebnis zu erhalten.
Zur Autorisierung zum Erstellen eines Dokuments:
var authorizationResult = await AuthorizationService
.AuthorizeAsync(user, document, Operations.Create);
Zur Autorisierung zum Lesen eines Dokuments:
var authorizationResult = await AuthorizationService
.AuthorizeAsync(user, document, Operations.Read);
Zur Autorisierung zum Löschen eines Dokuments:
var authorizationResult = await AuthorizationService
.AuthorizeAsync(user, document, Operations.Delete);
Zur Autorisierung zum Aktualisieren eines Dokuments:
var authorizationResult = await AuthorizationService
.AuthorizeAsync(user, document, Operations.Update);
Auf der AccessDocumentCrud-Seite der Beispiel-App:
- Leela (
leela@contoso.com) kann alsAdminundSuperUservollständige CRUD-Operationen auf Ressourcen ausführen. - Harry (
harry@contoso.com), als einzigerAdmin, kann Ressourcen erstellen, lesen und aktualisieren. - Sarah (
sarah@contoso.com) kann alsSuperUsernur Ressourcen löschen und lesen.