Laravel 8 e Autenticação JWT (tymon/jwt-auth) com Model customizada
Tags: laravel, php, jwt, auth
Published: 2021-05-14 23:16:02

Nesse artigo vou mostrar como implementar autenticação JWT (utilizando o pacote **tymon/jwt-auth**) em uma API com Laravel 8, utilizando uma Model diferente da padrão (Users). Ao final do texto, vou disponibilizar o link para o repositório contendo a implementação dos passos deste artigo :)

Então vamos lá!


## Instalação

Execute o comando para instalar o pacote

```bash
composer require tymon/jwt-auth
```
Publique o arquivo de configuração da biblioteca para sua pasta config, com o comando

```bash
php artisan vendor:publish - provider="Tymon\JWTAuth\Providers\LaravelServiceProvider"
```

Por fim, vamos gerar o JWT secret, utilizando o comando

```bash
php artisan jwt:secret
```

Esse comando vai adicionar a variável JWT_SECRET no seu arquivo `.env`

Em caso de qualquer dúvida sobre o 
processo de instalação, [acesse o link oficial do pacote](https://jwt-auth.readthedocs.io/en/develop/laravel-installation/) com instruções para a instalação.


## Configuração da Model

Como dito anteriormente, vamos utilizar uma Model diferente da Users para armazenar os dados de usuários. Em nosso caso, vamos criar uma nova Model chamada Employee. 

Para isso, vamos criar uma migration para criar uma tabela no nosso banco de dados com o mesmo nome da Model:

```bash
php artisan make:migration create_employee_table --create=employee
```

Nossa migration vai ter a mesma estrutura da migration de users que vem como padrão na instalação do Laravel, onde a única diferença será um campo a mais chamado "job_title". Fique a vontade para adicionar novas colunas, mas certifique-se que as colunas "email" e "password" serão criadas.

```php
Schema::create('employee', function (Blueprint $table) {
    $table->id();
    $table->string('name');
    $table->string('email')->unique();
    $table->string('password');
    $table->string('job_title');
    $table->timestamps();
});
```

Remova a migration para criação da tabela de users e rode as migrations

```bash
php artisan migrate
```

Crie a Model Employee

```bash
php artisan make:model Employee
```

*Obs: Adicione a variável $table na model, para passar o nome da tabela no singular, pois no momento de realizar a criação de usuário de teste (um pouco mais a frente nesse mesmo artigo), o Laravel vai por padrão tentar localizar a tabela no plural e vai ocasionar erro. Se você criou a tabela no plural (employees), pule o passo abaixo*

```bash
protected $table = 'employee';
```

Após a criação de nossa Model, vamos implementar a classe JWTSubject, implementando seus métodos. Além disso, vamos extender a classe Authenticatable do Laravel. No final, esse será o conteúdo de nossa Model

{% gist https://gist.github.com/WenLopes/29dbdc460badddfde6388caefa610342 %}

Muito bem, agora que temos nossa Model devidamente criada e configurada, é hora de configurarmos nosso provider de autenticação. Para isso, acesse o arquivo config/auth.php e vamos adicionar o novo índice 'employess' no array 'providers', contendo o driver (em nosso caso, vamos utilizar o Eloquent) e a model desejada.

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ulef6pu5dkta3gfgptmp.png)

Em seguida, no mesmo arquivo, vamos acessar o array "guards" e no array "api", vamos setar o driver "jwt" e o provider "employees" que acabamos de criar.

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/frt7ynfngrduztgqdm4o.png)
 
Por fim, vamos setar o guard "api" como o padrão de nossa aplicação. No mesmo arquivo, acesse o array "defaults" e defina o guard padrão como "api"

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p8a3nu9cmc5hv0a3w3md.png)

Feito isso, concluímos a configuração do nosso provider e o conteúdo final do arquivo config/auth.php será esse

{% gist https://gist.github.com/WenLopes/2ad0b52e47cd2163642e857bb21d4c05 %}


## Criando o controller e rota

Muito bem, agora que criamos e configuramos nossa Model, vamos criar o controller de autenticação para testar nossa implementação.

Crie o controller AuthController, com o mesmo conteúdo apresentado nesse [link do site oficial do pacote](https://jwt-auth.readthedocs.io/en/develop/quick-start/) e em seguida, crie a rota para realizar o login no arquivo `routes/api.php`

*Obs: Não se esqueça que a partir da versão 8 do Laravel, o controller deve ser importado no arquivo de rotas*

```php
use App\Http\Controllers\AuthController;

Route::post('auth/login', [AuthController::class, 'login'])->name('auth.login');
```

Para testar nosso endpoint, vamos criar um registro na tabela employee e utilizar os dados para autenticar.

No arquivo `DatabaseSeeder` , insira o seguinte conteúdo dentro do método `run`:

```php
\App\Models\Employee::create([
    'name' => 'Usuário de teste',
    'email' => 'usuario@teste.com.br',
    'password' => bcrypt( 'senha123' ),
    'job_title' => 'Gerente administrativo'
]);
```

E na sequência execute o comando:

```bash
php artisan db:seed
```

Por fim, utilize seu API client de preferência e consuma a rota de login **api/auth/login**, informando o email e senha criado na seeder. Se tudo ocorreu bem, o resultado será como o abaixo:

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hk1orw0ooahox8e6n6en.png)

E pronto, sua autenticação com model customizada está funcionando.

Como disse anteriormente, você pode baixar o projeto com essa implementação através do meu repositório no Github (link abaixo). Nesse repositório, estou utilizando Docker para infraestrutura, contendo Nginx, Mysql e o Laravel em sua versão 8. Além disso, implementei o [pattern Strategy](https://refactoring.guru/pt-br/design-patterns/strategy) para retornar mensagens em casos de erro de autenticação e/ou token expirado, onde no segundo caso, um novo token atualizado é retornado (estou preparando um novo artigo para abordar esse tema :).

[Clique aqui e acesse o repositório](https://github.com/WenLopes/laravel8-jwt)

Então é isso pessoal, em caso de dúvidas, deixe nos comentários. Obrigado e até a próxima