Hoje vamos lembrar os principais conceitos sobre a Autorização em aplicações ASP.NET Core. |
A autorização na ASP.NET Core determina se um usuário pode acessar uma
determinada rota, controlador, ação do controlador, recurso, etc, e , nesta
série de artigos vamos abordando os fundamentos da autorização, como ela
funciona e como usá-la no ASP.NET Core.
A autorização é o processo, que determina o que o usuário pode ou não fazer. É diferente da Autenticação, que determina quem é o usuário.
A autenticação sempre vem em primeiro lugar, antes
da autorização, ou seja, você está autorizado somente se estiver autenticado.
Dessa forma a autorização depende da autenticação para identificar o usuário.
Na ASP.NET Core, adicionamos o pipeline
Authentication ao Middleware usando o método
UseAuthentication no arquivo Startup ou no
arquivo Program:
...
app.UseRouting(); |
Geralmente adicionamos depois do UseRouting, para
que o middleware de autenticação saiba sobre a URL que está sendo acessada pelo
usuário.
A finalidade do middleware de autenticação é atualizar a propriedade
HttpContext.User com as informações sobre o usuário obtida de
ClaimsPrincipal.
A classe ClaimsPrincipal contém as declarações dos usuários e expõe uma coleção de identidades cada uma das quais e um tipo ClaimsIdentity, e, em geral esta coleção, que é acessada através da propriedade Identities, terá apenas um único elemento. Assim um usuário é do tipo ClaimPrincipal e é composto por um ClaimsIdentity.
Nota: ClaimsIdentity armazena informação sobre
o usuário como o status de autenticação e as claims.
Todo o middleware, que precisa saber quem é o usuário (por exemplo, middleware de autorização) deve vir após o UseAuthentication.
O middleware de autorização lê o ClaimsPrincipal de HttpContext.User e o usa para verificar se o usuário está autorizado.
Estratégias de
autorização
Podemos usar os serviços de autorização de várias maneiras para construir um
sistema de autorização robusto. Vejamos a seguir os principais :
Autorização declarativa
Nesse modo, usamos o atributo Authorize para
proteger uma página. O atributo Authorize descreve
como a página precisa ser protegida e o middleware de autorização lerá o
atributo e descobrirá como proteger a página.
Você pode configurar a Autorização Declarativa usando as seguintes formas
:
Autorização Simples
Autorização baseada em claims (declarações)
Autorização baseada em role (perfil/função)
Autorização baseada em Policy (política)
1. Autorização Simples
Na Autorização Simples, aplicamos o atributo [Authorize]
a um controlador, método Action ou Razor Page. Isso impedirá que os
usuários não autenticados acessem a página.
[Authorize]
public class HomeController : Controller
{
public ActionResult Login()
{
}
public ActionResult Logout()
{
}
}
|
Autorização baseada em Claims
(declarações)
Em uma estratégia de Autorização baseada em Claims,
criamos uma Política de Autorização e a mapeamos
para uma claim ou declaração (claims ou declarações) no método
ConfigureServices da classe Startup ou na
classe Program :
services.AddAuthorization(options => { options.AddPolicy("AdminOnly", policy => policy.RequireClaim("Admin")); }); |
builder.Services.AddAuthorization(options => { options.AddPolicy("AdminOnly", policy => policy.RequireClaim("Admin")); }); |
Nota:
Uma Claim é uma declaração que uma entidade
(um usuário ou outro aplicativo) faz sobre si mesma, é apenas uma
declaração. Por exemplo, uma lista de claims pode ter o nome do usuário,
o e-mail do usuário, a idade do usuário, a autorização do usuário para uma ação.
Na segurança baseada em role ou função, um usuário apresenta as credenciais
diretamente ao aplicativo.
Aplicamos a política a um controlador, Action ou Razor Page usando o atributo
Authorize. Isso não apenas interromperá os usuários
não autenticados, mas também os usuários autenticados se eles não
carregarem a declaração Admin.
[Authorize(Policy =
"AdminOnly")] public class AdminController: Controller { public ActionResult Login() {... } public ActionResult Logout() {...} } |
Observe que as Claims não podem ser usadas
diretamente usando o atributo Authorize. Você
precisa criar uma política para usá-las.
Autorização baseada em Role (função/perfil)
A autorização baseada em função é muito semelhante à autorização baseada em
claims, exceto que usa as roles ou perfis em vez de claims ou declarações.
Outra diferença é que você pode usar as Roles
diretamente usando o atributo Authorize.
[Authorize(Roles = "Admin")] public class AdminController : Controller { } |
Você também pode criar uma política usando o RequireRole
na classe de inicialização. e usar a política em vez de
Roles no Controlador :
builder.Services.AddAuthorization(options => { options.AddPolicy("AdminPolicy", policy => policy.RequireRole("Admin")); }); |
[Authorize(Policy =
"Admin")] public class AdminController: Controlador { } |
A autorização baseada em role existe devido à compatibilidade com versões
anteriores. É melhor evitar usá-la, pois pode ser preterido em um futuro
próximo.
Autorização baseada em Policy
(política)
As autorizações baseadas em claims e as baseadas em roles usam a
definição de uma Política nos bastidores. Mas se nos depararmos com
situações complexas, precisamos criar um esquema de autorização personalizado
baseado em políticas.
Os blocos de construção da autorização baseada na política são: a
política, o requisito e o manipulador de requisitos.
O requisito define o requisito de autorização;
O manipulador de requisitos contém a lógica que verifica o requisito. Um requisito pode ter mais de um manipulador;
Uma Política pode conter mais de um requisito;
Autorização baseada em recursos usando políticas
O middleware Authorization, que usa o atributo Authorize para verificar as
permissões, o executa muito antes da execução do manipulador de página ou do
método Action. Portanto, ele não tem acesso aos dados ou recursos nos quais a
página ou o método Action opera.
Por exemplo, pegue um documento que tenha um autor. Somente o Autor pode editar
o documento. Os outros usuários só podem visualizar o documento. Para
implementar a segurança acima, precisamos recuperar o documento do servidor,
verificar seu autor e decidir se permite a edição ou não. A autorização
declarativa com o atributo Authorize não pode lidar com essa situação.
Assim, escrevemos o código para validar o direito do usuário no próprio método,
injetando o serviço de Autorização na página/controlador. Em seguida, usamos o
método AuthorizeAsync para acionar manualmente uma
autorização.
Funciona assim:
1- O UseRouting resolve as solicitações HTTP recebidas e constrói um Endpoint;
2- O middleware de autenticação constrói a ClaimsPrincipal dos cookies ou
do token JWT e atualiza o HttpContext.User;
3- O request chega ao middleware de autorização. Verifica se permite o acesso ao
URL para o usuário;
4- Se a autorização for bem-sucedida, o request prosseguirá normalmente para o
middleware do endpoint e concluirá;
5- Se a autorização falhar, o middleware retornará um erro;
Se a autorização falhar, existe duas possibilidades : Ou o usuário não está
autenticado ou está autenticado, mas não autorizado.
1. O usuário não está autenticado
Se o usuário não for autenticado, o middleware de autorização invoca o
ChallengeResult no manipulador de autenticação.
Em um aplicativo Web, o manipulador redirecionará o usuário para a página de
login. Em um aplicativo de API, ele retorna uma resposta de erro
401 não autorizado.
2. O usuário não está autorizado
Se o usuário for autenticado, mas não autorizado, o middleware de autorização
invocará o ForbidResult no manipulador de
autenticação.
Em um aplicativo Web, o manipulador redirecionará o usuário para a página da Web
Acesso negado. Em um aplicativo API, ele retorna uma resposta de erro
403 Forbidden
E estamos conversados...
"E é evidente que pela lei ninguém será justificado
diante de Deus, porque o justo viverá pela fé."
Gálatas 3:11
Referências: