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.
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:
Um tipo de Requisitos que deriva de IAuthorizationRequirement e que contém campos que especificam os detalhes do requisito. No exemplo, este é um campo de idade para o tipo de amostra
MinimumAgeRequirement
.Um manipulador que implementa AuthorizationHandler<TRequirement>, onde T é o tipo de IAuthorizationRequirement que o manipulador pode satisfazer. O manipulador deve implementar o HandleRequirementAsync método, que verifica se um contexto especificado que contém informações sobre o usuário satisfaz o requisito.
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
Autenticação ASP.NET Core
https://learn.microsoft.com/aspnet/core/security/authentication/identityAutorização ASP.NET Core
https://learn.microsoft.com/aspnet/core/security/authorization/introductionAutorização baseada em função
https://learn.microsoft.com/aspnet/core/security/authorization/rolesAutorização personalizada baseada em políticas
https://learn.microsoft.com/aspnet/core/security/authorization/policiesAutenticação e autorização em APIs mínimas \ https://learn.microsoft.com/aspnet/core/fundamentals/minimal-apis/security