Trabalhando com Bearer Tokens no Flask com JWT

Neste artigo nós aprenderemos como trabalhar com autorização no Flask com JWT.

Uma parte fundamental no desenvolvimento web, principalmente depois da popularização das single page applications, é o uso de autorização de nossas APIs através do uso de Bearer Tokens.

Porém, antes de iniciarmos os nossos trabalhos no Flask com JWT, vamos dar uma olhada primeiramente no que é o JWT.

O que é JWT?

JWT é a abreviação de JSON Web Tokens, e trata-se de um padrão aberto e compacto da IETF (RFC 7519) para transferência de ‘claims’ entre duas ou mais partes.




ietf logo

 

Trata-se de uma maneira segura de se transferir informações, pelo fato do conteúdo ser assinado digitalmente.

Quando utilizamos JWT, o json trafegado entre as aplicações é composto por três partes: Header, Payload e Signature.

JSON Web Tokens – Header

Essa é a parte do JWT que informa como ele será processado.




Um header típico de um JWT é semelhante ao exemplo abaixo:


Onde os campos typ  e alg  são as informações do tipo do objeto, e o algorítimo de hash utilizado.

JSON Web Tokens – Payload

O payload, que também é comumente chamado de claim, é o conteúdo em si que será trafegado.

Entenda claims como as informações, que normalmente é do usuário e/ou de quem está realizando a requisição, entre outras informações relacionadas.

RFC 7519 define uma série de informações padrões, apesar de nenhuma ser obrigatória.




As informações definidas pela IETF são:

iss Issuer
sub Subject
aud Audience
exp Expiration time
nbf Not before
iat Issued at
jti JWT ID

JSON Web Tokens – Signature

Esta é a parte que fica mais interessante.

A assinatura de um JWT é criada a partir do header codificado, do payload codificado e mais uma chave.

Abaixo você confere o exemplo de uma assinatura que está disponível no site jwt.io:

Criando o nosso projeto Flask com JWT

Vamos começar o nosso projeto agora.

Para este artigo, nós iremos utilizar os seguintes pacotes:


Porém, antes de mais nada, como de costume, vamos criar o nosso ambiente utilizando o virtualenv:


Agora que já estamos com o nosso ambiente criado, vamos criar um arquivo chamado requirements.txt  e vamos adicionar os pacotes que eu mencionei anteriormente. Logo após isso, basta executar:

Criando a classe de Usuário

Para que possamos conceder autorização de utilização para um usuário, nós primeiro precisamos aceitar um.

Para isso, nós vamos utilizar a seguinte classe:


Acima nós criamos duas classes. A classe User  nós utilizaremos para persistência, através do SQLAlchemy.

Já a classe UserSchema  é para trabalhar com os requests e responses. Nós utilizamos o pacote marshmallow para isso.

Foram adicionados dois métodos na classe User , que é para gerar um hash  para a senha informada do usuário, e para validar uma determinada senha informada.

Nós utilizamos o pacote passlib  para isso. Você pode conferir um pouco mais sobre este grande pacote no artigo Como Trabalhar com Hashes em Python Utilizando Passlib.

Gerando o Primeiro Token

Agora que nós já temos tanto a nossa classe para persistência do usuário, quanto o mapeamento do nosso request, vamos criar um endpoint para testar a criação de usuários e a emissão dos tokens.

Primeira Versão do Projeto

Com o nosso endpoint criado, vamos levantar o nosso projeto e tentar criar alguns usuários / tokens.


E ao realizar um request para a nossa api através do postman, temos o resultado esperado:

novo usuario

Separando Um Pouco as Responsabilidades

Agora que já temos o nosso teste rodando, e podemos ver que conseguimos emitir um token com sucesso, vamos separar pelo menos um pouco as responsabilidades da nossa api.

Vamos deixar um endpoint para a criação do usuário, e outro para efetuar o login:

Criando o Endpoint para Atualizar o Token

Ao realizarmos o login, nós devolvemos tanto o access token, quanto o refresh token.

O refresh token serve para que, quando o access token perca a validade, o usuário possa gerar um novo access token sem precisar reenviar as informações de login.

Para isso, nós iremos criar um novo endpoint, e utilizaremos o decorator disponibilizado pelo Flask-JWT-Extend: jwt_refresh_token_required .

Ele verificará se nós estamos enviando um refresh token em nossa requisição, para que possamos emitir um novo access token.

Lidando com Requisições Não Autorizadas

Assim como nos outros casos que já vimos, lidar com uma requisição não autorizada no Flask-JWT-Extended é tão simples quanto decorar uma função.

Isso porque o Flask-JWT-Extended fornece para nós o decorator jwt.unauthorized_loader .

Com ele, nós podemos anotar uma função que será invocada ao recebermos uma requisição não autorizada.

Ou seja, para todas as rotas que nós protegermos, este método será chamado caso a requisição não possua um token devidamente validado e autorizado.

Protegendo as Nossas Rotas

Bem, talvez essa seja a parte mais importante do nosso artigo sobre Flask com JWT.

Afinal, todo este trabalho serve apenas para que possamos proteger as nossas rotas!

Para garantirmos que um determinado endpoint esteja autorizado devidamente, nós precisaremos de apenas um decorator oferecido pelo Flask-JWT-Extended: o jwt_required e/ou o fresh_jwt_required.

Nós utilizaremos aqui o  jwt_required, que verificará se a requisição possui um access token válido.

Como nós já criamos um tratamento para requisições não autorizadas, não precisamos nos preocupar com mais anda, e podemos apenas decorar a nossa rota:


E ao realizarmos um request com um token válido, receberemos a resposta corretamente:

flask com jwt - autorizado

E agora, caso resolvermos retirar o header com a autorização, nós receberemos como retorno:

flask com jwt - nao autorizado

Flask com JWT – Projeto Final

O código inteiro do projeto está no github.

Sinta-se a vontade para clonar o projeto e fazer todas as alterações que você precise!

Aliás, colocar a mão na massa é a melhor maneira de aprender!

Conclusão

Este é um exemplo bem simples de como podemos implementar autorização no flask com jwt, de maneira rápida e fácil.

Nós utilizamos o pacote Flask-JWT-Extended para este exemplo, mas ele não é o único pacote disponível para esta tarefa!

Aliás, por baixo dos panos, o Flask-JWT-Extended utiliza o pacote PyJWT para trabalhar com os tokens.

Vale a pena dar uma conferida neste pacote também!

E ai, o que achou?

Como sempre, não esqueça de deixar um comentário com eventuais dúvidas, ou críticas e sugestões!

Um grande abraço!

Links Importantes e Referências




Leave a Reply