Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Este artigo descreve como autorizar usuários para acesso aos recursos do aplicativo.
Em um aplicativo, um recurso normalmente é representado por uma classe C# que inclui dados armazenados em uma coleção, como uma byte[] matriz. A classe geralmente contém metadados adicionais relativos ao recurso, como um identificador de recurso exclusivo, datas, autores, informações de origem e um nome amigável para exibição em uma interface do usuário. A coleção que contém dados de recurso geralmente é carregada de conteúdo de arquivo físico, um objeto de armazenamento em nuvem, um objeto na memória ou dados de um banco de dados.
A autorização baseada em recursos requer atenção especial em aplicativos ASP.NET Core. A avaliação de atributo ocorre antes da associaçã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, o aplicativo deve invocar um método de autorização personalizado — uma abordagem conhecida como autorização imperativa.
Este artigo usa exemplos de componentes Razor e se concentra em cenários de autorização Blazor para o ASP.NET Core 3.1 ou versão posterior. Para Razor Pages e as orientações sobre MVC, que se aplicam a todas as versões do ASP.NET Core, consulte os seguintes recursos:
- Autorização baseada em recursos em ASP.NET Core Razor Páginas
- Autorização baseada em recurso no ASP.NET Core MVC
Os exemplos neste artigo usam construtores primários, disponíveis no C# 12 (.NET 8) ou posterior. Para obter mais informações, consulte Declarar construtores primários para classes e structs (tutorial de documentação do C#) e construtores primários (Guia do C#).
Aplicativo de exemplo
O Blazor Web App exemplo deste artigo é o BlazorWebAppAuthorization aplicativo de exemplo (dotnet/AspNetCore.Docs.Samples repositório GitHub) (como baixar). O aplicativo de exemplo usa contas semeadas com objetos de documento pré-configurados para demonstrar os exemplos neste artigo. Para obter mais informações, consulte o arquivo README do exemplo (README.md).
Caution
Este aplicativo de exemplo usa um banco de dados na memória para armazenar informações do usuário, o que não é adequado para cenários de produção. O aplicativo de exemplo destina-se apenas a fins de demonstração e não deve ser usado como ponto de partida para aplicativos de produção.
Usar autorização imperativa
A autorização é implementada como um IAuthorizationService, que é registrado na coleção de serviços na inicialização do aplicativo pela estrutura ASP.NET Core. O serviço é disponibilizado para Razor componentes e outras classes por meio de injeção de dependência:
@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) a serem avaliados:
Task<AuthorizationResult> AuthorizeAsync(
ClaimsPrincipal user,
object resource,
IEnumerable<IAuthorizationRequirement> requirements);
No exemplo a seguir, que é totalmente explicado na seção Criar um manipulador baseado em recursos , o recurso protegido é carregado em um objeto personalizado Document . Uma sobrecarga de AuthorizeAsync é invocada para determinar se o usuário atual tem permissão para acessar o documento com base na política de autorização "SameAuthorPolicy". Se authorizationResult.Succeeded for igual a true, o usuário está autorizado para o documento porque é o autor do documento (Document.Author corresponde ao Name do usuário):
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");
...
}
}
Criar um manipulador baseado em recursos
A criação de um manipulador de autorização baseado em recursos é semelhante à criação de um manipulador de requisitos sem formatação. Crie uma classe de requisito personalizada e implemente uma classe de manipulador de requisitos. Para obter mais informações sobre como criar uma classe de requisito, consulte Autorização baseada em política: Requisitos.
A seguinte classe de demonstração Document é usada:
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 de manipulador especifica o requisito e o tipo de recurso. O exemplo a seguir demonstra um manipulador utilizando 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 obter mais informações sobre como criar políticas de autorização, consulte Autorização baseada emPolicy no ASP.NET Core.
O componente a seguir AccessDocument chama uma AuthorizeAsync sobrecarga para determinar se o usuário atual tem permissão para exibir um documento com base na política de autorização "SameAuthorPolicy". Se authorizationResult.Succeeded for true, o usuário está autorizado para o documento porque é o autor do documento (Document.Author corresponde ao Name do usuário).
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}.";
}
}
}
No aplicativo de exemplo, cada usuário do aplicativo tem acesso autorizado ao documento semeado que ele criou.
Requisitos operacionais
Para tomar decisões com base nos resultados das operações CRUD (Criar, Ler, Atualizar, Excluir), use a OperationAuthorizationRequirement classe auxiliar. A classe auxiliar permite que você escreva um único manipulador em vez de uma classe individual para cada tipo de operação. A classe a seguir Operations estabelece todos os quatro tipos de operação 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 manipulador DocumentAuthorizationCrudHandler de autorização a seguir valida a operação com base no recurso, na identidade do usuário (função) em alguns casos e na propriedade Name do requisito:
- Todos os usuários podem ler documentos.
- Somente os usuários na
Adminfunção podem criar e atualizar documentos. - Somente os usuários na
SuperUserfunção podem excluir 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;
}
}
Onde os serviços são registrados no aplicativo:
builder.Services.AddSingleton<IAuthorizationHandler, DocumentAuthorizationCrudHandler>();
Chame a sobrecarga de AuthorizeAsync com a operação para retornar 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 excluir 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 do aplicativo de AccessDocumentCrud exemplo:
- Leela (
leela@contoso.com), como umAdmineSuperUser, pode executar operações CRUD completas em recursos. - Harry (
harry@contoso.com), sendo apenas umAdmin, pode criar, ler e atualizar recursos. - Sarah (
sarah@contoso.com), sendo a únicaSuperUser, pode excluir e ler recursos.