Autorização baseada em declarações no ASP.NET Core

Quando uma identidade é criada, ela pode pertencer a uma ou mais funções. Por exemplo, Tracy pode pertencer às funções Administrator e User, enquanto Scott pode pertencer apenas à funçãoUser. A forma como essas funções são criadas e gerenciadas depende do repositório de backup do processo de autorização. As funções são expostas ao desenvolvedor por meio do método IsInRole na classe ClaimsPrincipal. AddRoles deve ser adicionado aos serviços de função.

Embora as funções sejam declarações, nem todas as declarações são funções. Dependendo do emissor de identidade, uma função pode ser uma coleção de usuários que podem aplicar declarações para membros do grupo, bem como uma declaração real sobre uma identidade. No entanto, as declarações devem ser informações sobre um usuário individual. Usar funções para adicionar declarações a um usuário pode confundir o limite entre o usuário e suas declarações individuais. Essa confusão é o motivo pelo qual os modelos de SPA não são projetados em torno de funções. Além disso, para organizações que migram de um sistema herdado local, a proliferação de funções ao longo dos anos pode significar que uma declaração de função seja muito grande para ser contida em um token utilizável por SPAs. Para proteger SPAs, consulte Usar Identity para proteger um back-end da API Web para SPAs.

Adicionar serviços de função ao Identity

Registre serviços de autorização baseados em função no Program.cs chamando AddRoles com o tipo de função na configuração Identity do aplicativo. O tipo de função no exemplo a seguir é IdentityRole:

builder.Services.AddDefaultIdentity<IdentityUser>( ... )
    .AddRoles<IdentityRole>()
    ...

O código anterior requer o pacote Microsoft.AspNetCore.Identity.UI e uma diretiva using para Microsoft.AspNetCore.Identity.

Adicionando verificações de função

Verificações de autorização baseadas em função:

  • São declarativas e especificam funções das quais o usuário atual deve ser membro para acessar o recurso solicitado.
  • São aplicados a Páginas Razor, controladores ou ações dentro de um controlador.
  • Não pode ser aplicado no nível do manipulador da Página Razor. Devem ser aplicados à Página.

Por exemplo, o código a seguir limita o acesso a qualquer ação no AdministrationController para usuários que são membros da função Administrator:

[Authorize(Roles = "Administrator")]
public class AdministrationController : Controller
{
    public IActionResult Index() =>
        Content("Administrator");
}

Várias funções podem ser especificadas como uma lista separada por vírgulas:

[Authorize(Roles = "HRManager,Finance")]
public class SalaryController : Controller
{
    public IActionResult Payslip() =>
                    Content("HRManager || Finance");
}

O SalaryController só é acessível por usuários que são membros da função HRManagerou da função Finance.

Quando vários atributos são aplicados, um usuário de acesso deve ser membro de todas as funções especificadas. A amostra a seguir exige que um usuário seja um membro de ambas função PowerUsere funçãoControlPanelUser:

[Authorize(Roles = "PowerUser")]
[Authorize(Roles = "ControlPanelUser")]
public class ControlPanelController : Controller
{
    public IActionResult Index() =>
        Content("PowerUser && ControlPanelUser");
}

O acesso a uma ação pode ser limitado aplicando atributos de autorização de função adicionais no nível da ação:

[Authorize(Roles = "Administrator, PowerUser")]
public class ControlAllPanelController : Controller
{
    public IActionResult SetTime() =>
        Content("Administrator || PowerUser");

    [Authorize(Roles = "Administrator")]
    public IActionResult ShutDown() =>
        Content("Administrator only");
}

No controlador anterior ControlAllPanelController:

  • Os membros da função Administrator ou da função PowerUser podem acessar o controlador e a ação SetTime.
  • Somente os membros da função Administrator podem acessar a ação ShutDown.

Um controlador pode ser bloqueado, mas permitir acesso anônimo e não autenticado a ações individuais:

[Authorize]
public class Control3PanelController : Controller
{
    public IActionResult SetTime() =>
        Content("[Authorize]");

    [AllowAnonymous]
    public IActionResult Login() =>
        Content("[AllowAnonymous]");
}

Para Páginas Razor, [Authorize] pode ser aplicado por:

[Authorize(Policy = "RequireAdministratorRole")]
public class UpdateModel : PageModel
{
    public IActionResult OnPost() =>
         Content("OnPost RequireAdministratorRole");
}

Importante

Os atributos de filtro, incluindo AuthorizeAttribute, só podem ser aplicados a PageModel e não podem ser aplicados a métodos específicos do manipulador de página.

Verificações de função baseadas em política

Os requisitos de função também podem ser expressos usando a sintaxe de política, em que um desenvolvedor registra uma política na inicialização do aplicativo como parte da configuração do serviço de autorização. Normalmente, isso ocorre no arquivo Program.cs:

var builder = WebApplication.CreateBuilder(args);

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

builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("RequireAdministratorRole",
         policy => policy.RequireRole("Administrator"));
});

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

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

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

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

As políticas são aplicadas usando a propriedade Policy no atributo [Authorize]:

[Authorize(Policy = "RequireAdministratorRole")]
public IActionResult Shutdown()
{
    return View();
}

Para especificar várias funções permitidas em um requisito, especifique-as como parâmetros para o método RequireRole:

var builder = WebApplication.CreateBuilder(args);

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

builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("ElevatedRights", policy =>
          policy.RequireRole("Administrator", "PowerUser", "BackupAdministrator"));
});

var app = builder.Build();

O código anterior autoriza os usuários que pertencem às funções Administrator, PowerUser ou BackupAdministrator.

Quando uma identidade é criada, ela pode pertencer a uma ou mais funções. Por exemplo, Tracy pode pertencer às funções Administrador e Usuário, enquanto Scott pode pertencer apenas à função Usuário. A forma como essas funções são criadas e gerenciadas depende do repositório de backup do processo de autorização. As funções são expostas ao desenvolvedor por meio do método IsInRole na classe ClaimsPrincipal.

É recomendável não usar Funções como declarações, mas sim usar declarações. Ao usar SPAs (Aplicativos de Página Única), consulte Usar Identity para proteger um back-end da API Web para SPAs.

Adicionando verificações de função

Verificações de autorização baseadas em função:

  • São declarativas.
  • São aplicados a Razor Pages, controladores ou ações dentro de um controlador.
  • Não pode ser aplicado no nível do manipulador da Página Razor. Devem ser aplicados à Página.

As verificações de autorização baseadas em função especificam de quais funções o usuário atual deve ser membro para acessar o recurso solicitado.

Por exemplo, o código a seguir limita o acesso a qualquer ação no AdministrationController para usuários que são membros da função Administrator:

[Authorize(Roles = "Administrator")]
public class AdministrationController : Controller
{
    public IActionResult Index() =>
        Content("Administrator");
}

Várias funções podem ser especificadas como uma lista separada por vírgulas:

[Authorize(Roles = "HRManager,Finance")]
public class SalaryController : Controller
{
    public IActionResult Payslip() =>
                    Content("HRManager || Finance");
}

O SalaryController só é acessível por usuários que são membros da função HRManagerou da função Finance.

Se você aplicar vários atributos, um usuário de acesso deverá ser membro de todas as funções especificadas. A amostra a seguir exige que um usuário seja um membro de ambas função PowerUser e função ControlPanelUser:

[Authorize(Roles = "PowerUser")]
[Authorize(Roles = "ControlPanelUser")]
public class ControlPanelController : Controller
{
    public IActionResult Index() =>
        Content("PowerUser && ControlPanelUser");
}

Você pode limitar ainda mais o acesso aplicando atributos de autorização de função adicionais no nível da ação:

[Authorize(Roles = "Administrator, PowerUser")]
public class ControlAllPanelController : Controller
{
    public IActionResult SetTime() =>
        Content("Administrator || PowerUser");

    [Authorize(Roles = "Administrator")]
    public IActionResult ShutDown() =>
        Content("Administrator only");
}

Se várias políticas forem aplicadas nos níveis de controlador e ação, todos os atributos deverão ser aprovados antes que o acesso seja concedido:

[Authorize(Roles = "Administrator")]
public class ControlAllPanelController2 : Controller
{
    public IActionResult SetTime() =>
        Content("Administrator only");

    [Authorize(Roles = "PowerUser")]
    public IActionResult ShutDown() =>
        Content("Administrator && PowerUser");
}

No controlador anterior ControlAllPanelController:

  • Os membros da função Administrator ou da função PowerUser podem acessar o controlador e a ação SetTime.
  • Somente os membros da função Administrator podem acessar a ação ShutDown.

Você também pode bloquear um controlador, mas permitir acesso anônimo e não autenticado a ações individuais.

[Authorize]
public class Control3PanelController : Controller
{
    public IActionResult SetTime() =>
        Content("[Authorize]");

    [AllowAnonymous]
    public IActionResult Login() =>
        Content("[AllowAnonymous]");
}

Para Páginas Razor, [Authorize] pode ser aplicado por:

[Authorize(Policy = "RequireAdministratorRole")]
public class UpdateModel : PageModel
{
    public ActionResult OnPost()
    {
    }
}

Importante

Os atributos de filtro, incluindo AuthorizeAttribute, só podem ser aplicados a PageModel e não podem ser aplicados a métodos específicos do manipulador de página.

Verificações de função baseadas em política

Os requisitos de função também podem ser expressos usando a sintaxe de política, em que um desenvolvedor registra uma política na inicialização como parte da configuração do serviço de autorização. Normalmente, isso ocorre em ConfigureServices() em seu arquivo Startup.cs.

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews();
    services.AddRazorPages();

    services.AddAuthorization(options =>
    {
        options.AddPolicy("RequireAdministratorRole",
             policy => policy.RequireRole("Administrator"));
    });
}

As políticas são aplicadas usando a propriedade Policy no atributo [Authorize]:

[Authorize(Policy = "RequireAdministratorRole")]
public IActionResult Shutdown()
{
    return View();
}

Se você quiser especificar várias funções permitidas em um requisito, poderá especificá-las como parâmetros para o método RequireRole:

options.AddPolicy("ElevatedRights", policy =>
                  policy.RequireRole("Administrator", "PowerUser", "BackupAdministrator"));

Este exemplo autoriza usuários que pertencem às funções Administrator.PowerUser ou BackupAdministrator.

Adicionar serviços de função ao Identity

Acrescente AddRoles para adicionar serviços de função:

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<ApplicationDbContext>(options =>
        options.UseSqlServer(
            Configuration.GetConnectionString("DefaultConnection")));
    services.AddDefaultIdentity<IdentityUser>()
        .AddRoles<IdentityRole>()
        .AddEntityFrameworkStores<ApplicationDbContext>();

    services.AddControllersWithViews();
    services.AddRazorPages();
}