Utilizando JWT no Lumen — parte 1

Utilizando JWT no Lumen — parte 1

Esse é meu primeiro artigo aqui na plataforma, portanto ainda estou me adaptando ao método de postagem.

Resolvi fazer este artigo pois eu senti há algum tempo atrás a necessidade de fazer uma autenticação via JWT porém que o cliente tenha um limite de requisições por mês, assim a empresa poderá monetizar as quotas de uso de acordo com a sua necessidade.

Para este artigo em questão, por ser consumo de API, irei utilizar o Lumen (Versão do artigo 8.2.1, mas caso seu PHP for inferior à 7.3 ele vai instalar automaticamente o 7.x) ao invés do Laravel, mesmo que sejam basicamente a mesma coisa, o Lumen te dá a possibilidade de iniciar com quase nenhuma dependência fazendo com que seja bem mais rápido no quesito API, pois você só habilita o que realmente for utilizar!

Repositório no GIT

Para quem quiser o repositório completo para ir olhando o artigo e tiver alguma dúvida segue o repositório (porém fique atento que o Lumen que foi desenvolvido é o 8, provavelmente você terá problemas caso seja inferior ao 7)

brasizza/lumen-jwt

Iniciando seu ambiente

Vamos começar com o link do POSTMAN para fazer os testes

JWT

Iremos utilizar o composer para iniciar o projeto do lumen na sua verão mais atual com o comando

composer create-project laravel/lumen  --prefer-dist lumen-jwt

onde o lumen-jwt é o nome do seu projeto, que pode ser qualquer nome que queira!

Feita a instalação você terá que inicar o Lumen via linha de comando já que ele não conta com o php artisan serve do laravel. Então vamos iniciar com o seguinte comando (php -S 0.0.0.0:8000 -t public — eu coloco 0.0.0.0 pra poder acessar de qualquer lugar, seja localhost ou 127.0.0.1 ou ip interno caso você vá utilizar em outro ambiente)

Criando a estrutura do banco de dados

Para utilizar o JWT é necessário um banco de dados para inserir os usuários. Então vamos utilizar o comando do artisan para criar a estrutura da tabela de usuários

php artisan make:migration create_users_table --create=user

Feito isso você precisa ir no seu .env e alterar os dados do seu banco de dados e executar o comando php artisan migrate que vai colocar os campos corretos na sua tabela

NOTA IMPORTANTE

Caso você esteja usando uma versão do Lumen anterior à 8 não será criado nada dentro dessa migration create_users_table, pois na versão 8 ele cria os campos automaticamente. Caso esse seja o seu caso, utilize o migration abaixo.
Agradecimento ao
Fabianosantosilva

Alterando o app.php e incluindo o config/auth.php

A coisa boa do Lumen como falei acima é que você só habilita o que usa, assim o ambiente de APIs ficam mais rápidas sem consumo de serviços que não são importantes.

Inicialmente vamos no arquivo app.php que se encontra na pasta bootstrap/app.php

A primeira coisa que faremos é descomentar as seguintes linhas

$app->withFacades();
$app->withEloquent();

Isso fará com que o seu Lumen trabalhe com o eloquent e que seja registrada as Facades.

Após isso precisamos descomentar a linha

$app->register(App\Providers\AuthServiceProvider::class);

E adicionar a linha do JWT

$app->register(Tymon\JWTAuth\Providers\LumenServiceProvider::class);

E descomentar o seguinte código do middleware

$app->routeMiddleware(['auth' => App\Http\Middleware\Authenticate::class, ]);

Por fim iremos criar um arquivo auth.php dentro de uma pasta config, na raiz do projeto assim como existe no Laravel

Crie a pasta config no mesmo nível da pasta app e crie um arquivo chamado auth.php

Feito isso seu sistema já está pronto para receber as coisas pertinentes ao JWT.

Enfim iniciando com o JWT

Infelizmente todos os passos anteriores eram necessários para que todos estivessem na mesma página no quesito de instalação e configuração do Lumen.

Para instalar o pacote do JWT iremos utilizar o composer com o seguinte comando

composer require tymon/jwt-auth

Ao final da instalação iremos executar o comando

php artisan jwt:secret

que vai gerar no seu arquivo .env uma variável chamada JWT_SECRET, porém caso não gere, crie no final do seu arquivo com o resultado do secret:
jwt-auth secret [Nx87BInH1JgokFt2brxtToBefhz2LXK9deAvMKJgW9OidDjIWfm3ZRvZK0gSyLax] set successfully.

Ai é só copiar o código que está ente chaves e incluir no seu .env : JWT_SECRET=xxxxxxxxxx
Também iremos já incluir uma diretiva de JWT_TTL=60 que será usada mais tarde, mas já que estamos alterando o arquivo .env faremos isso uma vez só.

Alterando o model de usuários

Nas versões mais atuais do Lumen, como esta que estamos fazendo é um pouco diferente a alteração do Model porém mais simples, basta somente você colocar o Implement do JWTSubject

Porém uma coisa importante. Eu particularmente gosto de usar Mutators para criação da senha e outras coisas que facilitam a vida na hora de programar.

Para quem nunca viu o mutator serve para alterar valor em tempo de associação ou recuperação de propriedades e recomendo muito sua utilização.

NOTA IMPORTANTE
Este model foi feito para funcionar no Lumen 8, existem alguns uses que não existem no 7 , portanto eu recomendo você pegar o seu User.php, e somente adicionar o implements JWTSubject e colocar os métodos que faltam como os mutators e os métodos override do JWT!
De novo agradecimento ao
Fabianosantosilva por testar no Lumen 7!

Como vocês podem ver, eu criei um setPasswordAttribute que vai só criar um hash quando eu associar meu $user->password=’123456′ ele internamente vai criar o hash dentro da minha propriedade

Usando uma Trait para facilitar nossos retornos

Ao longo dos anos de trabalho com o php eu acabei encontrando uma Trait que eu uso em todos os meus projetos para facilitar o meu desenvolvimento e retorno para APIs RestFull. com ela você pode retornar um success ou erro, incluindo o HTTP CODE que você quer retornar para a aplicação de um jeito fácil

Para isso crie também na pasta app uma pasta chamada Traits e dentro dela coloque o seguinte código em um arquivo chamado apiResponser.php

Modificando o controller raiz

Como iremos usar o mesmo método para várias classes nós iremos alterar o Controller q é o controller que extende os demais controllers do sistema. Então basicamente vc vai criar neste artigo somente um método, que é o método que vai retornar o token em formato json e http code 200

Finalmente!! Nossa classe de autenticação

Tivemos que fazer vários passos até chegar no primordial! mas necessário para que não tenha nenhuma dúvida do passo a passo no desenvolvimento da sua API JWT, que eu tenho certeza que na próxima vez que fizer será mais fácil e fluído.

Vamos criar uma classe chamada nesse projeto de AuthController.php
O que eu sempre faço é abrir o arquivo ExampleController.php e salvar com o nome que eu quero, para não ter q digitar muita linha de código.

Inicialmente nosso banco não tem nenhum registro, então primeiro precisamos criar uma rota para registar ao menos um usuário para fazer a movimentação das APIS.

Vamos criar nosso método register, JUNTO com um método de validação somente para que tenha validação de campos obrigatórios e etc para teste.

O código está separado dos demais métodos pois vamos fazer um a um para o entendimento

Criamos um método register e um método isRegisterValid onde nele fazemos a validação dos campos que vierem do POST, sendo obrigatórios, únicos no caso do email de um jeito ultra fácil e também a quantidade mínima de caracteres pro email

Pra o registro acontecer precisamos criar a rota que vai chamar este método. Portanto lá no arquivo web.php iremos incluir nosso código. Como estamos utilizando o Lumen como API eu sempre gosto de colocar o prefixo da chamada como API , ai nosso código sempre será http://url/api/xxxxx, assim fica mais fácil o entendimento do que está na API

Feito isso já podemos subir nossa aplicação com o comando passado lá em cima
php -S 0.0.0.0:8000 -t public

Com tudo executando certinho você pode ir lá no Postman e fazer (que você pode pegar no começo deste artigo. Se tudo ocorreu do jeito que deveria ocorrer você deverá receber o json de sucesso no seu Postman parecido com esse

Sinal que tudo ocorreu como deveria ter ocorrido, vamos partir para o próximo método que é o de login e autenticação do seu usuário para utilizar o token JWT

Também neste caso irei criar um método de login e o método isLoginValid para fazer a validação dos campos inseridos

o método login vai pegar o e-mail e a senha vindo do post, e fazer a tentativa de encontrar o usuário com aquele login e aquela senha.
O ponto importante aqui é o setTTL que é o Time To Live do token. lá em cima colocamos essa variável JWT_TTL=60 portanto seu token irá durar 1 hora, porém esse valor pode ser alterado no prórprio .env, ou caso não queira, será utilizado o padrão de 60 minutos (1 hora). Além disso também tem a chamada do método que está no pai Controller.php que vai retornar os dados do token para a aplicação que está chamando, ou caso não encontre ele irá mandar um Response:HTTP_NOT_FOUND , ou o código 404, que dá na mesma.

Então vamos criar a rota que vai receber este método de login também lá no web.php

Feito isso, também poderá testar no Postman colocando o e-mail e a senha cadastradas anteriormente no método register

Quando a API não encontrar o usuário irá retornar 404

Quando encontrar , irá retornar o token , o tipo e o tempo de expiração

Feito isso, podemos agora criar um método que só poderá ser acessado depois que o usuário se autenticar e receber o token, vamos chamar o método de me
Nesse código já vou postar o controller inteiro, pois é o último método deste arquivo

o método me é somente a recuperação simples do usuário e sua exibição na tela, mas com isso é o essencial para completar o ciclo, inclusive com método que só pode ser acessado depois do token

Agora vamos incluir essa rota dentro do web.php incluindo o middleware de autenticação exclusivamente para o método em questão

Se tudo ocorreu como planejado você receberá o seguinte json

Tratando Exceptions de Token expirado ou token inválido

Nem tudo é perfeito. o token expira, porém este é o intuito do token, que ele expire e que o acesso ao seu sistema seja por um tempo limitado.

Para fazermos esse tipo de alteração você precisa ir lá no seu middleware/Authenticate.php

Espero que tenha ficado claro e como ficou muito extenso no próximo artigo irei demostrar como colocar um limite de uso de alguns endpoints por mês ou para possível monetizacão de abertura de mais cotas para o usuário. e depois disso, iremos modificar o método de login para utilizar o padrão de mercado, login via client_id e client_secret com simulação de envio de email pro cliente de boas vindas com os dados cadastrais utilizando o mailtrap.

Caso queira ir para a segunda parte direto por aqui, só clicar abaixo!

Utilizando JWT no Lumen — parte 2 (Incluindo mais um método de autenticação)