Sobre autorização em microsserviços .NET e aplicativos Web

Gorjeta

Este conteúdo é um trecho do eBook, .NET Microservices Architecture for Containerized .NET Applications, disponível no .NET Docs ou como um PDF para download gratuito que pode ser lido offline.

.NET Microservices Architecture for Containerized .NET Applications eBook cover thumbnail.

Após a autenticação, ASP.NET Core Web APIs precisam autorizar o acesso. Esse processo permite que um serviço disponibilize APIs para alguns usuários autenticados, mas não para todos. A autorização pode ser feita com base nas funções dos usuários ou com base na política personalizada, que pode incluir a inspeção de declarações ou outras heurísticas.

Restringir o acesso a uma rota MVC ASP.NET Core é tão fácil quanto aplicar um atributo Authorize ao método action (ou à classe do controlador se todas as ações do controller exigirem autorização), conforme mostrado no exemplo a seguir:

public class AccountController : Controller
{
    public ActionResult Login()
    {
    }

    [Authorize]
    public ActionResult Logout()
    {
    }
}

Por padrão, adicionar um atributo Authorize sem parâmetros limitará o acesso a usuários autenticados para esse controlador ou ação. Para restringir ainda mais uma API a estar disponível apenas para usuários específicos, o atributo pode ser expandido para especificar as funções ou políticas necessárias que os usuários devem satisfazer.

Implementar autorização baseada em função

ASP.NET Core Identity tem um conceito interno de funções. Além dos usuários, ASP.NET Core Identity armazena informações sobre diferentes funções usadas pelo aplicativo e controla quais usuários são atribuídos a quais funções. Essas atribuições podem ser alteradas programaticamente com o RoleManager tipo que atualiza funções no armazenamento persistente e o UserManager tipo que pode conceder ou revogar funções dos usuários.

Se você estiver autenticando com tokens de portador JWT, o middleware de autenticação de portador JWT Core ASP.NET preencherá as funções de um usuário com base nas declarações de função encontradas no token. Para limitar o acesso a uma ação ou controlador MVC a usuários em funções específicas, você pode incluir um parâmetro Roles na anotação Authorize (atributo), conforme mostrado no fragmento de código a seguir:

[Authorize(Roles = "Administrator, PowerUser")]
public class ControlPanelController : Controller
{
    public ActionResult SetTime()
    {
    }

    [Authorize(Roles = "Administrator")]
    public ActionResult ShutDown()
    {
    }
}

Neste exemplo, somente usuários nas funções Administrador ou PowerUser podem acessar APIs no controlador do Painel de Controle (como executar a ação SetTime). A API de Desligamento é ainda mais restrita para permitir acesso apenas a usuários na função de Administrador.

Para exigir que um usuário esteja em várias funções, use vários atributos Authorization, conforme mostrado no exemplo a seguir:

[Authorize(Roles = "Administrator, PowerUser")]
[Authorize(Roles = "RemoteEmployee ")]
[Authorize(Policy = "CustomPolicy")]
public ActionResult API1 ()
{
}

Neste exemplo, para chamar API1, um usuário deve:

  • Estar na função de Administrador ou PowerUser e

  • Estar na função RemoteEmployee e

  • Satisfaça um manipulador personalizado para autorização CustomPolicy.

Implementar autorização baseada em políticas

As regras de autorização personalizadas também podem ser escritas usando políticas de autorização. Esta seção fornece uma visão geral. Para obter mais informações, consulte o ASP.NET Workshop de autorização.

As políticas de autorização personalizadas são registradas no método Startup.ConfigureServices usando o serviço. AddAuthorization método. Esse método usa um delegado que configura um argumento AuthorizationOptions.

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

    options.AddPolicy("EmployeesOnly", policy =>
        policy.RequireClaim("EmployeeNumber"));

    options.AddPolicy("Over21", policy =>
        policy.Requirements.Add(new MinimumAgeRequirement(21)));
});

Como mostrado no exemplo, as políticas podem ser associadas a diferentes tipos de requisitos. Depois que as políticas são registradas, elas podem ser aplicadas a uma ação ou controlador passando o nome da política como o argumento Policy do atributo Authorize (por exemplo, [Authorize(Policy="EmployeesOnly")]) As políticas podem ter vários requisitos, não apenas um (como mostrado nestes exemplos).

No exemplo anterior, a primeira chamada AddPolicy é apenas uma maneira alternativa de autorizar por função. Se [Authorize(Policy="AdministratorsOnly")] for aplicado a uma API, somente os usuários na função Administrador poderão acessá-la.

A segunda AddPolicy chamada demonstra uma maneira fácil de exigir que uma determinada reivindicação esteja presente para o usuário. O RequireClaim método também toma opcionalmente os valores esperados para a declaração. Se os valores forem especificados, o requisito será atendido somente se o usuário tiver uma declaração do tipo correto e um dos valores especificados. Se você estiver usando o middleware de autenticação de portador JWT, todas as propriedades JWT estarão disponíveis como declarações de usuário.

A política mais interessante mostrada aqui está no terceiro AddPolicy método, porque usa um requisito de autorização personalizado. Usando requisitos de autorização personalizados, você pode ter um grande controle sobre como a autorização é executada. Para que isso funcione, você deve implementar estes tipos:

Se o usuário atender ao requisito, uma chamada para context.Succeed indicará que o usuário está autorizado. Se houver várias maneiras pelas quais um usuário pode satisfazer um requisito de autorização, vários manipuladores podem ser criados.

Além de registrar requisitos de política personalizada com AddPolicy chamadas, você também precisa registrar manipuladores de requisitos personalizados por meio da injeção de dependência (services.AddTransient<IAuthorizationHandler, MinimumAgeHandler>()).

Um exemplo de um requisito de autorização personalizado e manipulador para verificar a idade de um usuário (com base em uma DateOfBirth declaração) está disponível na documentação de autorização do ASP.NET Core.

Autorização e APIs mínimas

ASP.NET suporta APIs mínimas como alternativa às APIs baseadas em controlador. As políticas de autorização são a maneira recomendada de configurar a autorização para APIs mínimas, como este exemplo demonstra:

// Program.cs
builder.Services.AddAuthorizationBuilder()
  .AddPolicy("admin_greetings", policy =>
        policy
            .RequireRole("admin")
            .RequireScope("greetings_api"));

// build the app

app.MapGet("/hello", () => "Hello world!")
  .RequireAuthorization("admin_greetings");

Recursos adicionais