ASP .NET Core MVC - Protegendo uma WEB API - VI
Neste artigo vamos continuar a criação de uma WEB API usando a ASP .NET Core 3.0 para a seguir mostrar como consumir a API em uma aplicação ASP .NET Core MVC. |
Continuando a quinta parte do artigo vou mostrar agora uma forma de proteger a nossa Web API usando chaves.
Até o momento a nossa Web API ApiReservas (criada na primeira parte do artigo) pode ser acessada por qualquer usuário anônimo.
Geralmente desejamos restringir o acesso a nossa API e existem muitas formas de proteger uma WEB API como:
Neste artigo eu vou mostrar como usar uma chave de API ou API Key.
O que é uma API Key ?
Uma chave de API é um pedaço de código atribuído a um programa, desenvolvedor ou usuário específico que é usado sempre que a entidade faz uma chamada para uma API. Essa chave geralmente é uma longa sequência de caracteres gerados que seguem um conjunto de regras de geração especificado pela autoridade que os cria. Exemplo: TP84UTvzJKds1Jomx8gIbTXcEEJSUilGqpxCcmnx&yldoidjdç.
Após a criação da conta ou o registro do aplicativo, muitos provedores de API atribuem chaves de API a seus desenvolvedores, permitindo que funcionem de maneira semelhante a um nome de usuário e senha de conta. As chaves da API são únicas e, por isso, muitos provedores optaram por usá-las como um tipo de camada de segurança, impedindo a entrada e outros direitos a quem não puder fornecer a chave para o serviço solicitado.
De forma bem simples, o cliente terá que enviar a chave da API junto com o request, e, a chave será verificada no controlador da API e se estiver correta a resposta será enviada ao cliente.
Uma forma muito usada de enviar a chave para a API é usar o cabeçalho da requisição HTTP.
Antes de mostrar uma implementação bem simples de utilização dessa abordagem cabe destacar que ela não é recomendada para aplicações comerciais com dados sensíveis pois apresenta diversas vulnerabilidades.
No nosso exemplo vamos restringir o acesso a nossa API de forma que somente clientes autorizados poderão alterar uma reserva e incluir uma reserva.
Ajustando o código da Web API - ApiReservas
Para isso vamos alterar os métodos Action Put e Post da nossa API conforme abaixo:
1- POST
[HttpPost] public IActionResult Post([FromBody] Reserva res) { if (!Authenticate()) return Unauthorized("401 - Não Autorizado"); return Ok(repository.AddReserva(new Reserva { Nome = res.Nome, InicioLocacao = res.InicioLocacao, FimLocacao = res.FimLocacao })); } |
2- PUT
[HttpPut] public IActionResult Put([FromForm] Reserva res) { if (!Authenticate()) { return Unauthorized("401 - Não Autorizado"); } return Ok(repository.UpdateReserva(res)); } |
Em ambos os métodos Action definimos um método Authenticate que irá retornar true ou false conforme a chave secrete for ou não válida. Se não for válida emitimos uma mensagem de '41 - Não Autorizado'.
Precisamos agora incluir o método Authenticate() no controlador ReservasController do projeto ApiResevas:
bool Authenticate() { var chavesSecretas = new[] { "numsey@2019", "twly@wzpou#1pcmb8cnm45uz@m0yr@" }; StringValues key = Request.Headers["Key"]; int count = (from t in chavesSecretas where t == key select t).Count(); return count == 0 ? false : true; } |
Neste código estamos definindo as chaves secretas que estamos esperando. Veja que podemos definir mais de uma chave secreta.
Depois obtemos a chave secreta enviada pelo cliente no header do request obtendo o valor de ['key'].
A seguir verificamos se a chave enviada existe em nosso array de chaves secretas e retornamos false se não existir e true se a chave existir.
Ajustando o código do projeto Mvc_Reservas
Precisamos agora ajustar o código do controlador ReservasController do projeto Mvc_Reservas.
Vamos ajustar os métodos Action HttpPost AddReserva e HttpPost UpdateReserva :
1- HttpPost AddReserva
[HttpPost] public async Task<IActionResult> AddReserva(Reserva reserva) { Reserva reservaRecebida = new Reserva();
using (var httpClient = new HttpClient()) using (var response = await httpClient.PostAsync(apiUrl, content)) |
Neste código incluimos o header do request o valor da chave secreta. Para este exemplo estou incluindo uma senha incorreta - numsey@2018 - (a senha correta é numsey@2019). Assim poderemos testar quando o usuário não esta autorizado.
A seguir verificamos se no response existe o código 401, e, em caso positivo retornamos para a view e exibimos a mensagem.
2- HttpPost UpdateReseva
[HttpPost] public async Task<IActionResult> UpdateReserva(Reserva reserva) { Reserva reservaRecebida = new Reserva();
using (var httpClient = new HttpClient()) var content = new MultipartFormDataContent(); content.Add(new StringContent(reserva.ReservaId.ToString()), "ReservaId"); using (var response = await httpClient.PutAsync(apiUrl, content)) |
Neste código realizamos o mesmo procedimento que no método anterior. Aqui estamos incluindo no header a senha secreta correta.
Ajustando as Views para exibir a mensagem
Agora para poder exibir as mensagens ao usuário vamos ajustar as views AddReserva e UpdateReserve incluindo o código abaixo no fim do formulário:
<h3
class="alert">@ViewBag.Result</h3>
Pronto. Agora é só alegria...
Testando as opções para Incluir e Atualizar uma reserva obtems o resultado a seguir:
Nota: Para testar excute o projeto ApiReservas e a seguir o projeto Mvc_Reservas.
Temos assim a nossa implementação funcionando, e agora somente os usuários que enviarem a chave secreta no header do request pode incluir e alterar reservas.
Deixo aqui um alerta que esta abordagem não deve ser usada em projetos críticos no ambiente de produção pois a chave secreta pode ser obtida pela decompilação do projeto e por outros meios mais avançados.
Os grandes problemas com as chaves de API ocorrem quando os usuários finais, e não os desenvolvedores, começam a fazer chamadas de API com essas chaves, que geralmente expõem sua API a riscos de segurança e gerenciamento. O que se resume é que as API Keys não são, por natureza, uma solução completa.
Embora possam ser perfeitamente adequadas para fins de somente leitura, são uma solução muito fraca para corresponder à complexidade de um sistema de API de alto uso. Sempre que você começa a integrar outras funcionalidades, como gravação, modificação, exclusão e muito mais, entra necessariamente no domínio de Identificação, Autenticação e Autorização.
Na próxima parte do artigo veremos como receber dados em diferentes formatos.
Pegue o código dos projetos aqui: ApiReservas_2.zip e Mvc_Reservas_2.zip
Que nos consola em toda a nossa tribulação, para que também possamos consolar os
que estiverem em alguma tribulação, com a consolação com que nós mesmos somos
consolados por Deus."
2 Coríntios 1:3,4
Referências:
ASP .NET Core - Implementando a segurança com ...
ASP.NET Core MVC - Criando um Dashboard ...
ASP .NET Core - Apresentando Razor Pages -
ASP .NET Core MVC - CRUD básico com ADO .NET
ASP .NET Core - Implementando e consumindo JWT
ASP .NET Core - Criando uma API CRUD - I
ASP .NET Core - Criando sua primeira Web API