/ #aspnet #aspnetcore 

Autorização em APIs ASP.Net Core

Em um artigo anterior eu falei sobre a criação de uma API de Autenticação utilizando ASP.Net Core. Hoje quero falar um pouco sobre como podemos fazer a Autorização de nossos usuários dentro das APIs.

Sendo que no artigo citado acima eu fiz uma breve introdução sobre os conceitos de Autenticação e Autorização, então, se você não viu corre lá e depois volte aqui.

Os recursos de autorização descritos neste artigo foram implementados a titulo de demonstração nesse projeto que está no meu Github.

Autorização baseada em Roles

Quando uma identidade de usuário é criada, ela pode ter Roles (papéis) associadas ao usuário. Por exemplo, um usuário pode ter o “papel” de Administrador, enquanto outro pode ter o “papel” de Usuário, sendo que cada um possui permissões de acesso diferentes dentro do sistema.

Usamos as Roles para autorizar o acesso do usuário à determinados recursos dentro da aplicação. Sendo essa a forma mais comum de autorização.

Para autorizar o acesso dos usuários em nossas APIs, seja usando Roles ou Policies, conforme veremos mais adiante, devemos fazer uso de um atributo chamado AuthorizeAttribute. Para isso basta adicionar esse atributo na Controller ou Action que queremos proteger.

No exemplo acima, o acesso à essa Controller será permitido apenas aos usuários que possuem a role Administrator. Usuários que não possuem essa role receberão um erro (403 Forbidden) ao tentar acessar esse recurso.

Abaixo temos o exemplo do payload de um token JWT com uma role User.

JWT com a role User

Ao chamar a API no Postman passando esse token JWT no header Authorization, o acesso é negado, pois o usuário não possui a role Administrator que é requerida para acessar essa Controller.

Acesso negado à API com HTTP Status Code 403 Forbidden

Já neste exemplo, temos o payload de um usuário com role de administração, no caso Administrator.

JWT com a role Administrator

Ao chamar a mesma API com esse token JWT, o acesso é permitido e uma listagem dos usúarios cadastrados é exibida.

Acesso concedido à API com HTTP Status Code 200 OK

Veja que o atributo Authorize deve ser colocado em cada classe que queremos autorizar o acesso, mesmo que não informemos nenhuma Role específica. Nesse caso, quando nenhuma Role é informada, apenas uma identidade de usuário válida já basta para autorizar o acesso.

Temos que concordar que adicionar esse atributo em cada Controller ou Action que queremos proteger pode se tornar algo trabalhoso e chato dependendo do tamanho da aplicação. Mas existe uma forma de aplicar a autorização de forma global para toda a API, para isso devemos fazer uso de Filtros do ASP.Net MVC, mais precisamente do filtro chamado AuthorizeFilter.

Com isso, toda a API irá requerer ao menos um token válido. Nas Controllers ou Actions que você desejar acesso anônimo, use o atributo AllowAnonymous.

Autorização baseada em Policies

Outra forma de autorizar o acesso à determinados recursos é fazendo uso de Policies.

Uma Policy pode ser composta por um ou mais requirements que uma identidade de usuário deve satisfazer.

As Policies são mais flexíveis quando comparadas à Roles, e com elas podemos elaborar melhor o acesso aos recursos.

Você precisa criar um Requirement que deverá ser satisfeito durante a autorização do usuário, usando a interface IAuthorizationRequirement. No meu exemplo criei uma classe que representa o requirement necessário para permitir a exclusão de um usuário na aplicação.

Após criar o requirement, precisamos criar um handler que será responsável por validar se ele foi satisfeito, para isso fazemos uso da classe AuthorizationHandler<TRequirement> informando em sua definição o requirement que ela irá tratar.

Nesse exemplo hipotético, essa classe irá verificar se o usuário possui a role Administrator, e também se ele possui a permissão para exclusão de um usuário, nesse caso ele deverá possuir a claim Permissions com o valor CanDeleteUser, que será passado através da propriedade RequiredPermission do requirement conforme veremos mais adiante.

Para que tudo isso funcione você deve configurar a Policy utilizando o método AddAuthorization da interface IServiceCollection.

Você deve informar um nome para a policy, aqui ela se chama DeleteUserPolicy, e então adicionar o requirement que quer validar, em meu exemplo temos o DeleteUserRequirement. Também deve ser informado o valor esperado para esse requirement que é CanDeleteUser, nesse caso o usuário precisa ter esse valor na claim Permissions caso contrário o requirement não será satisfeito.

Além disso, também é necessário injetar o handler DeleteUserRequirementHandler no containder de DI.

Com tudo isso pronto, basta utilizar novamente o atributo Authorize, informando o nome da Policy que queremos utilizar, nesse caso DeleteUserPolicy.

Somente usuários que possuem a role Administrator, e que possuem a permissão adequada, neste caso CanDeleteUser, conseguirão acessar a action DeleteAccount.

Abaixo temos o exemplo de um payload JWT em que o usuário possui a role Administrator, e a permissão CanDeleteUser.

JWT com role Administrator e claim Permissions com valor CanDeleteUser

Authorization Service

Além do atributo Authorize que vimos anteriormente, podemos usar a interface IAuthorizationService manualmente. Ela é utilizada internamente pelos filtros de autorização do ASP.Net Core.

Você pode injetar essa interface no construtor da classe onde quer autorizar o acesso e fazer uso do método AuthorizeAsync. Após ser chamado, esse método irá disparar o handler associado ao requirement informado, da mesma forma como o atributo Authorize faria.

Conclusão

Roles e Policies representam a forma mais comum e segura de autorizar o acesso à determinado recurso em nossas aplicações, e fazendo o correto uso deles podemos customizar o acesso à nossas APIs de forma simples.

Espero que tenham gostado e se tiverem dúvidas, críticas ou sugestões entrem em contato.

Abraços!

Referências

Foto da capa por Chris Barbalis em Unsplash

Deixe seu comentário