Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
Este artigo descreve como autorizar utilizadores a aceder a recursos da aplicação.
Numa aplicação, um recurso é tipicamente representado por uma classe C# que inclui dados armazenados numa coleção, como um byte[] array. A classe normalmente contém metadados adicionais relacionados com o recurso, como um identificador único de recurso, datas, autores, informação de origem e um nome amigável para exibição numa interface. A coleção que contém dados de recursos é geralmente carregada a partir de conteúdos físicos de ficheiros, de um objeto de armazenamento na cloud, de um objeto em memória ou de dados de uma base de dados.
A autorização baseada em recursos requer atenção especial nas aplicações ASP.NET Core. A avaliação de atributos ocorre antes da ligação de dados e antes da execução de qualquer método que carregue um recurso. A autorização declarativa com um [Authorize] atributo não é suficiente para autorização baseada em recursos. Em vez disso, a aplicação deve invocar um método de autorização personalizado — uma abordagem conhecida como autorização imperativa.
Este artigo utiliza exemplos de componentes Razor e foca-se em cenários de autorização Blazor para ASP.NET Core 3.1 ou posteriores. Para as Páginas Razor e as orientações MVC, que se aplicam a todas as versões de ASP.NET Core, consulte os seguintes recursos:
- Autorização baseada em recursos em ASP.NET Core Razor Páginas
- Autorização baseada em recursos no ASP.NET Core MVC
Exemplos neste artigo utilizam construtores primários, disponíveis em C# 12 (.NET 8) ou posteriores. Para mais informações, consulte Declarar construtores primários para classes e estruturas (tutorial de documentação C#) e Construtores primários (Guia C#).
Aplicativo de exemplo
O Blazor Web App exemplo deste artigo é a BlazorWebAppAuthorization aplicação de exemplo (dotnet/AspNetCore.Docs.Samples repositório GitHub) (como descarregar). A aplicação de exemplo utiliza contas seeded com objetos de documento pré-configurados para demonstrar os exemplos deste artigo. Para mais informações, consulte o ficheiro README do exemplo (README.md).
Atenção
Esta aplicação de exemplo utiliza uma base de dados em memória para armazenar informações do utilizador, o que não é adequado para cenários de produção. A aplicação de exemplo destina-se apenas a fins de demonstração e não deve ser usada como ponto de partida para aplicações de produção.
Use uma autorização imperativa
A autorização é implementada como um IAuthorizationService, que é registado na coleção de serviços no arranque da aplicação pelo framework ASP.NET Core. O serviço é disponibilizado a componentes Razor e outras classes através de injeção de dependências:
@using Microsoft.AspNetCore.Authorization
@inject IAuthorizationService AuthorizationService
IAuthorizationService tem duas sobrecargas do método AuthorizeAsync. Uma das sobrecargas aceita um recurso e um nome de política:
Task<AuthorizationResult> AuthorizeAsync(
ClaimsPrincipal user,
object resource,
string policyName);
A outra sobrecarga aceita um recurso e uma coleção de requisitos (IAuthorizationRequirement) para avaliar:
Task<AuthorizationResult> AuthorizeAsync(
ClaimsPrincipal user,
object resource,
IEnumerable<IAuthorizationRequirement> requirements);
No exemplo seguinte, que é totalmente explicado na secção Criar um manipulador baseado em recursos , o recurso protegido é carregado num objeto personalizado Document . É invocada uma AuthorizeAsync sobrecarga para determinar se o utilizador atual pode aceder ao documento com base na política de autorização "SameAuthorPolicy". Se authorizationResult.Succeeded for true, o utilizador está autorizado para o documento porque é o autor do documento (Document.Author corresponde ao Name do utilizador):
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");
...
}
}
Crie um handler baseado em recursos
Criar um gestor de autorização baseado em recursos é semelhante a criar um gestor de requisitos simples. Crie uma classe de requisitos personalizada e implemente uma classe handler de requisitos. Para mais informações sobre a criação de uma classe de requisitos, consulte Autorização baseada em políticas: Requisitos.
A seguinte classe de demonstração Document é utilizada:
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; }
}
A classe handler especifica o requisito e o tipo de recurso. O exemplo seguinte demonstra um manipulador a utilizar um SameAuthorRequirement requisito e um Document recurso.
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 { }
Registre o requisito e o manipulador em Program.cs:
builder.Services.AddAuthorizationBuilder()
.AddPolicy("SameAuthorPolicy", policy =>
policy.Requirements.Add(new SameAuthorRequirement()));
builder.Services.AddSingleton<IAuthorizationHandler, DocumentAuthorizationHandler>();
Registre o requisito e o manipulador em Startup.ConfigureServices:
services.AddAuthorization(options =>
{
options.AddPolicy("SameAuthorPolicy", policy =>
policy.Requirements.Add(new SameAuthorRequirement()));
});
services.AddSingleton<IAuthorizationHandler, DocumentAuthorizationHandler>();
Para mais informações sobre a criação de políticas de autorização, consulte Autorização baseada em políticas em ASP.NET Core.
O componente seguinte AccessDocument invoca uma sobrecarga de AuthorizeAsync para determinar se o utilizador atual tem permissão para ver um documento de acordo com a política de autorização "SameAuthorPolicy". Se authorizationResult.Succeeded for igual a true, o utilizador está autorizado para o documento porque é o autor do documento (Document.Author corresponde ao Name do utilizador).
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}.";
}
}
}
Na aplicação de exemplo, cada utilizador da aplicação está autorizado a aceder ao documento inicial de que é autor.
Requisitos operacionais
Para tomar decisões com base nos resultados das operações CRUD (Crear, Lê, Atualizar, Eliminar), use a OperationAuthorizationRequirement classe auxiliar. A classe helper permite-lhe escrever um único handler em vez de uma classe individual para cada tipo de operação. A seguinte Operations classe estabelece todos os quatro tipos de operações CRUD:
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) };
}
O seguinte DocumentAuthorizationCrudHandler processador de autorização valida a operação com base no recurso, na identidade do utilizador (função) em alguns casos e na propriedade Name do requisito:
- Todos os utilizadores podem ler documentos.
- Só os utilizadores do
Admincargo podem criar e atualizar documentos. - Apenas os utilizadores da
SuperUserfunção podem eliminar documentos.
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;
}
}
Quando os serviços estão registados na aplicação:
builder.Services.AddSingleton<IAuthorizationHandler, DocumentAuthorizationCrudHandler>();
Chame a sobrecarga de AuthorizeAsync com a operação para devolver o resultado da autorização.
Para autorização para criar um documento:
var authorizationResult = await AuthorizationService
.AuthorizeAsync(user, document, Operations.Create);
Para autorização para ler um documento:
var authorizationResult = await AuthorizationService
.AuthorizeAsync(user, document, Operations.Read);
Para autorização para eliminar um documento:
var authorizationResult = await AuthorizationService
.AuthorizeAsync(user, document, Operations.Delete);
Para autorização para atualizar um documento:
var authorizationResult = await AuthorizationService
.AuthorizeAsync(user, document, Operations.Update);
Na página AccessDocumentCrud da aplicação de exemplo:
- Leela (
leela@contoso.com), comoAdmineSuperUser, pode realizar operações CRUD completas em recursos. - Harry (
harry@contoso.com), como o únicoAdmin, pode criar, ler e atualizar recursos. - Sarah (
sarah@contoso.com), sendo apenas umSuperUser, pode eliminar e ler recursos.