.NET Core + JWT + Polly + Refit: consumindo APIs seguras com simplicidade e resiliência

Renato Groffe
4 min readJan 20, 2020

--

Em um artigo anterior já abordei o uso da biblioteca Refit no consumo de APIs REST. O objetivo nesta ocasião foi demonstrar que a mesma constitui uma excelente alternativa ao uso da classe HttpClient (internamente o próprio Refit se vale de instâncias deste tipo), resultand em uma codificação muito mais simples e concisa:

ASP.NET Core + JWT + Refit: consumindo uma API protegida de forma descomplicada

O projeto Polly constitui outro exemplo de solução extremamente útil para Desenvolvedores .NET, simplificando em muito a implementação de mecanismos para tratamento de falhas e contribuindo para a construção de aplicações resilientes. Esta biblioteca também foi tema de um artigo que publiquei neste blog:

.NET Core + Polly + JWT: tratando de forma resiliente a expiração de tokens

Neste novo artigo demonstro como combinar o uso de Polly e Refit em uma aplicação .NET Core, possibilitando assim uma maior simplicidade e resiliência no consumo de uma API REST protegida por JWT e Refresh Tokens.

Implementando o consumo da API com Refit e Polly

A aplicação detalhada nesta seção fará uso da API disponibilizada no repositório a seguir:

ASP.NET Core 3.1 + JWT (JSON Web Token) + Identity Core + Entity Framework Core InMemory + Redis + Refresh Tokens

Já comentei sobre este mesmo projeto e o fluxo de consumo de uma API REST protegida por JWT e Refresh Tokens no seguinte post:

ASP.NET Core 3.1 + JWT + Refresh Tokens: exemplo de implementação

Quanto ao uso de Refit, o projeto aqui apresentado é uma variação do exemplo abordado no artigo que já mencionei sobre esta biblioteca.

A interação com a API protegida acontecerá na classe APIProdutoClient:

A autenticação e mesmo a obtenção de um novo token de acesso (JWT) via Refresh Token acontecerá por meio da interface ILoginAPI:

Em APIProdutoClient um objeto será gerado com base em tal interface, empregando para isto a classe RestService disponibilizada pelo Refit (através de uma chamada ao método For):

No método AutenticarComSenha podemos observar a autenticação empregando usuário e senha, com uma codificação muito mais simples do que a baseada na classe HttpClient:

A operação AutenticarComRefreshToken conta com um comportamento similar, porém se vale do Refresh Token para a obtenção de um novo token de acesso (JWT):

Foi implementada ainda uma Policy baseada no pattern Retry para tratamento de falhas envolvendo o uso de JWT, empregando para isto a classe AsyncRetryPolicy da biblioteca Polly e considerando em HandleInner exceções baseadas na classe ApiException (tipo este disponibilizado pelo Refit):

  • Conforme podemos observar no método CreateAccessTokenPolicy, uma resposta com status de Unauthorized (erro HTTP 401) fará com que se proceda com o envio do Refresh Token (via método AutenticarComRefreshToken);
  • Caso se trate de um Refresh Token inválido (o mais provável é que tenha expirado), a autenticação convencional ocorrerá através do método AutenticarComSenha.

A interface IProdutosAPI será empregada na interação com a API de produtos. Todos os métodos definidos neste tipo recebem como parâmetro o token de acesso (JWT), o qual está representado pela referência token (esta última marcada com o atributo Header):

Um método de extensão chamado ExecuteWithRefreshTokenAsync também foi criado (estendendo a classe AsyncRetryPolicy), tendo por objetivo simplificar o tratamento de falhas ao executar códigos sujeitos à expiração de tokens. O dicionário manipulado aqui evitará instruções duplicadas armazenando o token de acesso (JWT) e o Refresh Token no objeto de contexto utilizado por AsyncRetryPolicy:

Quanto ao consumo da API de produtos e o tratamento de falhas é necessário destacar:

  • No construtor de APIProdutosClient será gerada uma instância baseada em AsyncRetryPolicy (_jwtPolicy) para a execução de chamadas a esta API e já considerando todo o fluxo de tratamento de erros no caso de expiração dos tokens;
  • Um objeto baseado na interface IProdutosAPI será gerado por meio de uma chamada ao método For da classe RestService;
  • As ações dos métodos IncluirProduto e ListarProdutos foram bastante simplificadas tanto pelo uso de Refit (com um código mais enxuto se comparado à utilização de HttpClient), quanto por empregar a biblioteca Polly (dispensando blocos try-catch e loops para tentativas adicionais).

Na imagem a seguir há um exemplo de teste desta aplicação em que é possível observar:

  • Durante a segunda ação que envolve o cadastramento de um produto o token de acesso (JWT) e o Refresh Token expiraram, com isso resultando em uma nova autenticação;
  • Já na terceira ação foi esperada a expiração do token de acesso (JWT). Desta vez houve sucesso no uso do Refresh Token, com a exibição na sequência do resultado da consulta aos produtos cadastrados.

O código-fonte desta aplicação também foi disponibilizado no GitHub:

.NET Core 3.1 + Refit + Consumo de API REST + JWT + Refresh Tokens + Código Resiliente com Polly

--

--

Renato Groffe

Microsoft Most Valuable Professional (MVP), Multi-Plataform Technical Audience Contributor (MTAC), Software Engineer, Technical Writer and Speaker