ASP.NET - Autenticação com ApiKey

Neste artigo vamos entender um pouco mais sobre API Keys e como podemos trazer uma autenticação mais simplificadas as nossas APIs.

Autenticação e autorização

Antes de continuar neste artigo é importante ter bem definidos os conceitos de autenticação e autorização, conforme descrevi neste artigo.

Caso queira uma autenticação baseado em perfis, ou mesmo entender do que se tratam JWT, Token, Roles e Claims, veja este artigo onde pontuo todos estes itens.

ApiKey

O conceito de chaves de API ou ApiKey trata-se do envio de uma chave encriptada na URL ou cabeçalho da requisição.

Este modelo não deve ser utilizado em autenticação do lado do cliente, como aplicações em JavaScript por exemplo, visto que o usuário teria acesso a esta chave via browser.

Esta chave deve ser utilizada para autenticação de clientes que rodam do lado do servidor, como uma outra API por exemplo. Desta forma sua chave fica sempre no servidor (Ou banco de dados), em segredo.

O Azure Functions é um ótimo exemplo disto, sempre que chamamos uma função, precisamos informar o código de acesso a mesma, e ele se encarrega do processo de autenticação e autorização.

https://sua-function.azurewebsites.net/api/endpoint?code=MINHA_CHAVE_DE_API

Em resumo, ao invés de fazer um processo de autenticação convencional, enviando usuário e senha para receber um Token e depois enviando este Token no cabeçalho da requisição, enviamos diretamente esta chave que dá acesso a API.

Deste modo, temos a ApiKey como uma substituta da autenticação via usuário e senha que geraria um Token.

Segurança

Como você deve imaginar, esta informação é bem sensível e qualquer pessoa com sua ApiKey poderá fazer requisições para sua API, então é importante guardá-la com muito carinho.

Criando a aplicação

Para este processo, não vamos precisar instalar nenhum pacote adicional, apenas gerar um novo projeto ASP.NET do tipo webapi que criará uma API vazia.

dotnet new webapi -o MeuApiKey
cd MeuApiKey
dotnet watch run

Criando um atributo

Não existe muito mistério aqui, sabendo o conceito de ApiKey o que queremos é interromper uma requisição e verificar se ela existe na Query ou nos Headers.

Feito isto, precisamos validá-la, para garantir que ela é uma ApiKey válida. É o processo básico de autenticação e autorização.

A maneira mais fácil de realizar este procedimento é criar um atributo customizado, que no caso é apenas uma classe que herda de Attribute.

Para organizar melhor, crie uma pasta chamada Attributes na raiz da aplicação junto ao ApiKeyAttribute.cs dentro dela.

Nossa classe começa com as heranças e a utilização do AttributeUsage que limita o uso deste atributo a classes e métodos no caso.

[AttributeUsage(validOn: AttributeTargets.Class | AttributeTargets.Method)]
public class ApiKeyAttribute : Attribute, IAsyncActionFilter
{
...

Desta forma, poderemos utilizar uma notação [ApiKey] tanto na classe (Controller) quanto em um método (Action).

Definições

Para melhorar nosso código, vamos criar duas constantes, uma para o nome do parâmetro que vamos buscar e outro com a chave que vamos comparar.

private const string ApiKeyName = "api_key";
private const string ApiKey = "balta_demo_IlTevUM/z0ey3NwCV/unWg==";

Aqui está o ponto chave deste artigo, o ApiKey que definimos acima é a chave de acesso a toda API. Quem utilizar esta chave, "está no comando".

Você pode armazenar esta chave no AppSettings por exemplo, assim pode versionar seu código tranquilamente e substituir o valor dela durante o deploy.

Caso tenha dificuldades em lidar com esta situação de deploy e troca de configurações entre ambientes, leia este artigo que escrevi sobre GitHub Actions e Microsoft Azure.

De qualquer forma, a ideia aqui é ter uma chave (Ou várias) para saber se a requisição é valida. Posteriormente você pode melhorar isto, inclusive lendo as chaves do banco de dados por exemplo.

Interceptando a requisição

Ao herdar da classe Attribute e IAsyncActionFilter somos obrigados a implementar o método OnActionExecutionAsync, onde poderemos inspecionar a requisição atual.

Neste caso, vamos inspecionar o context.HttpContext.Request que possui tanto a propriedade Headers quanto Query, se referindo aos cabeçalhos e a URL da requisição respectivamente.

Logo, se queremos obter um valor da URL, utilizamos context.HttpContext.Request.Query, enquanto para obter um valor dos cabeçalhos utilizamos context.HttpContext.Request.Headers.

A única coisa que precisamos nos atentar é que podemos ter mais de um valor com o mesmo nome ou mesmo nenhum valor. Desta forma é recomendado utilizar a extensão TryGetValue para não ter exceções na execução do código.

[AttributeUsage(validOn: AttributeTargets.Class | AttributeTargets.Method)]
public class ApiKeyAttribute : Attribute, IAsyncActionFilter
{
    private const string ApiKeyName = "api_key";
    private const string ApiKey = "balta_demo_IlTevUM/z0ey3NwCV/unWg==";

    public async Task OnActionExecutionAsync(
        ActionExecutingContext context,
        ActionExecutionDelegate next)
    {
        if (!context.HttpContext.Request.Query.TryGetValue(ApiKeyName, out var extractedApiKey))
        {
            // Não encontrou
        }

        await next();
    }
}

Por fim, podemos utilizar o método next() para dar continuidade a requisição quando desejarmos.

ApiKey não encontrada

Caso nossa ApiKey não esteja presente na Query (Ou Headers, depende de como você escolheu utilizar), vamos atualizar o resultado do contexto atual e interromper a requisição.

if (!context.HttpContext.Request.Query.TryGetValue(ApiKeyName, out var extractedApiKey))
{
    context.Result = new ContentResult()
    {
        StatusCode = 401,
        Content = "ApiKey não encontrada"
    };
    return;
}

Note que para este caso utilizamos o código 401 - Unauthorized, pois não conter uma chave é um sinal que a requisição não está autenticada.

ApiKey inválida

Nosso próximo passo é verificar se a chave enviada é válida, e para isto vamos utilizar o método Equals da string, responsável por sua comparação com outro valor do mesmo tipo.

if (!ApiKey.Equals(extractedApiKey))
{
    context.Result = new ContentResult()
    {
        StatusCode = 403,
        Content = "Acesso não autorizado"
    };
    return;
}

Note que para este caso utilizamos o código 403 - Forbidden, pois a chave existe mas é inválida. Você poderia utilizar o 401 aqui também, é mais uma questão de visão e preferências.

ApiKey Attribute

A versão final do nosso atributo [ApiKey], definido na classe Attributes/ApiKeyAttribute.cs fica assim.

[AttributeUsage(validOn: AttributeTargets.Class | AttributeTargets.Method)]
public class ApiKeyAttribute : Attribute, IAsyncActionFilter
{
    private const string ApiKeyName = "api_key";
    private const string ApiKey = "balta_demo_IlTevUM/z0ey3NwCV/unWg==";

    public async Task OnActionExecutionAsync(
        ActionExecutingContext context,
        ActionExecutionDelegate next)
    {
        if (!context.HttpContext.Request.Query.TryGetValue(ApiKeyName, out var extractedApiKey))
        {
            context.Result = new ContentResult()
            {
                StatusCode = 401,
                Content = "ApiKey não encontrada"
            };
            return;
        }


        if (!ApiKey.Equals(extractedApiKey))
        {
            context.Result = new ContentResult()
            {
                StatusCode = 403,
                Content = "Acesso não autorizado"
            };
            return;
        }

        await next();
    }
}

Adicionando autenticação e autorização

Nosso próximo passo é informar a aplicação que estamos utilizando autenticação e autorização. Normalmente a linha app.UseAuthentication já vem no código, mas caso não esteja presente, fica assim.

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    ...
    app.UseRouting();

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

    app.UseEndpoints(endpoints => { endpoints.MapControllers(); });
}

IMPORTANTE a ordem de adição dos itens deve ser exatamente como acima. Se você inverter o UseAuthentication com o UseAuthorization por exemplo, não vai funcionar.

Utilizando o atributo ApiKey

Com tudo pronto, vamos utilizar nosso atributo no WeatherController.cs, adicionando-o a qualquer método. Neste exemplo, criei um método novo, do tipo GET para facilitar os testes.

[ApiController]
[Route("weather")]
public class WeatherForecastController : ControllerBase
{
    [HttpGet("")]
    [ApiKey]
    public IActionResult Get()
    {
        return Ok(new {message = "Você tem acesso!"});
    }
}

Testando a API

Agora vamos testar a API e se você utilizou um método GET como eu, basta chamar estes três endereços no seu browser.

https://localhost:5001/weather
https://localhost:5001/weather?api_key=12345
https://localhost:5001/weather?api_key=balta_demo_IlTevUM/z0ey3NwCV/unWg==

Na primeira requisição você deve receber um erro 401, pois não informamos o ApiKey. Na segunda você deve receber um erro 403 pois o ApiKey é inválido, e por fim, devemos conseguir visualizar a mensagem "Você tem acesso!".

Fontes

Populares

Priority Queue

Priority Queue ou fila prioritária é um tipo de lista inclusa no C# 10 que permite que seus itens...


Implicit Operators no C#

Implicit Operators permitem adicionar comportamentos de conversão a objetos Built In ou complexos...


ASP.NET 5 – Autenticação e Autorização com Bearer e JWT

Este artigo atualmente utiliza a versão 5.0.0-rc.1 do ASP.NET/.NET, o que significa que ainda não...


Clean Code - Guia e Exemplos

Saiba como manter seu código limpo (Clean Code) seguindo algumas práticas sugeridas pelo Robert C...


Git e GitHub - Instalação, Configuração e Primeiros Passos

Git é um sistema de controle de versões distribuídas, enquanto GitHub é uma plataforma que tem o ...


Compartilhe este artigo



Conheça o autor

Me dedico ao desenvolvimento de software desde 2003, sendo minha maior especialidade o Desenvolvimento Web. Durante esta jornada pude trabalhar presencialmente aqui no Brasil e Estados Unidos, atender remotamente times da ?ndia, Inglaterra e Holanda, receber 8x Microsoft MVP e realizar diversas consultorias em empresas e projetos de todos os tamanhos.





2.651

Aulas disponíveis

249

horas de conteúdo

64.156

Alunos matriculados

45.399

Certificados emitidos





Comece de graça agora mesmo!

Temos mais de 19 cursos totalmente de graça e todos com certificado de conclusão.

Começar


Prefere algo mais Premium?

Conheça nossos planos



Premium semestral

Compra única, parcelada em até
12x no cartão de crédito


12x R$

49

,78

=R$ 597,36
  • 6 meses de acesso
  • Acesso à todo conteúdo
  • Emissão de Certificado
  • Tira Dúvidas Online
  • 59 cursos disponíveis
  • 10 carreiras disponíveis
  • 161 temas de tecnologia
  • Conteúdo novo todo mês
  • Encontros Premium

Começar agora

Política de privacidade

Premium anual

Compra única, parcelada em até
12x no cartão de crédito


12x R$

84

,78

=R$ 1.017,36
  • 1 ano de acesso
  • Acesso à todo conteúdo
  • Emissão de Certificado
  • Tira Dúvidas Online
  • 59 cursos disponíveis
  • 10 carreiras disponíveis
  • 161 temas de tecnologia
  • Conteúdo novo todo mês
  • Encontros Premium

Começar agora

Política de privacidade



Precisa de ajuda?

Dúvidas frequentes



  • Posso começar de graça?

    Sim! Basta criar sua conta gratuita no balta.io e começar seus estudos. Nós contamos com diversos cursos TOTALMENTE gratuitos e com certificado de conclusão.

  • Vou ter que pagar algo?

    Nós temos cursos gratuitos e pagos, porém você não precisa informar nenhum dado de pagamento para começar seus estudos gratuitamente conosco. Os cursos gratuitos são completos e com certificado de conclusão, você não paga nada por eles.

    Porém, caso queira algo mais Premium , você terá acesso à diversos benefícios que vão te ajudar ainda mais em sua carreira.

  • Por onde devo começar?

    Siga SEMPRE as nossas Carreiras , elas vão te orientar em todos os sentidos. Os cursos já estão organizados em categorias e carreiras para facilitar seu aprendizado.
    Nossa sugestão para aprendizado é começar pelo Backend e seguindo para Frontend e Mobile.

    • Backend
    • Frontend
    • Mobile

  • Os cursos ensinam tudo que preciso?

    Nenhum curso no mundo vai te ensinar tudo, desculpa ser sincero! Os cursos são uma base, eles fornecem por volta de 30% do que você precisa aprender, o resto é com você, com dedicação e MUITA prática.

  • O que eu devo estudar?

    Java ou .NET? Angular ou React? Xamarin ou Flutter? A resposta é simples e direta: "Você já sabe o básico?"

    Se você ainda não sabe BEM o básico, ou seja, os fundamentos, OOP, SOLID, Clean Code, está perdendo tempo estudando Frameworks ou até coisas mais avançadas como Docker. Foque nos seus objetivos primeiro.
    Agora se você está indeciso sobre qual Framework estudar, a boa notícia é que o mercado neste momento está bem aquecido e você tem várias oportunidade. Desta forma o que levaríamos em conta para tomar esta decisão seria:

    • Já sei o básico
    • O Framework/Tecnologia tem mercado onde eu estou (região)
    • O Framework/Tecnologia é utilizado em uma empresa onde quero atual
    • O Framework/Tecnologia resolve meu problema
    • Eu gosto de utilizar o Framework/Tecnologia

  • Estou pronto para estudar no balta.io?

    Com certeza! O primeiro passo é começar e você pode fazer isto agora mesmo!

    Começar de graça

Ainda tem dúvidas?





Assine nosso Newsletter

Receba em primeira mão todas as nossas novidades.

Cadastrar


balta.io