DEV Community

Wendel Lopes
Wendel Lopes

Posted on • Edited on

10 1

Laravel 8 e Autenticação JWT (tymon/jwt-auth) com Model customizada

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



composer require tymon/jwt-auth


Enter fullscreen mode Exit fullscreen mode

Publique o arquivo de configuração da biblioteca para sua pasta config, com o comando



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


Enter fullscreen mode Exit fullscreen mode

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



php artisan jwt:secret


Enter fullscreen mode Exit fullscreen mode

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 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:



php artisan make:migration create_employee_table --create=employee


Enter fullscreen mode Exit fullscreen mode

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.



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


Enter fullscreen mode Exit fullscreen mode

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



php artisan migrate


Enter fullscreen mode Exit fullscreen mode

Crie a Model Employee



php artisan make:model Employee


Enter fullscreen mode Exit fullscreen mode

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



protected $table = 'employee';


Enter fullscreen mode Exit fullscreen mode

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

<?php
namespace App\Models;
use Tymon\JWTAuth\Contracts\JWTSubject;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
class Employee extends Authenticatable implements JWTSubject
{
use HasFactory, Notifiable;
protected $table = 'employee';
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'name',
'email',
'password',
'job_title'
];
/**
* Get the identifier that will be stored in the subject claim of the JWT.
*
* @return mixed
*/
public function getJWTIdentifier()
{
return $this->getKey();
}
/**
* Return a key value array, containing any custom claims to be added to the JWT.
*
* @return array
*/
public function getJWTCustomClaims()
{
return [];
}
}
view raw Employee.php hosted with ❤ by GitHub

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

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

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

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

<?php
return [
/*
|--------------------------------------------------------------------------
| Authentication Defaults
|--------------------------------------------------------------------------
|
| This option controls the default authentication "guard" and password
| reset options for your application. You may change these defaults
| as required, but they're a perfect start for most applications.
|
*/
'defaults' => [
'guard' => 'api',
'passwords' => 'users',
],
/*
|--------------------------------------------------------------------------
| Authentication Guards
|--------------------------------------------------------------------------
|
| Next, you may define every authentication guard for your application.
| Of course, a great default configuration has been defined for you
| here which uses session storage and the Eloquent user provider.
|
| All authentication drivers have a user provider. This defines how the
| users are actually retrieved out of your database or other storage
| mechanisms used by this application to persist your user's data.
|
| Supported: "session", "token"
|
*/
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'jwt',
'provider' => 'employees'
],
],
/*
|--------------------------------------------------------------------------
| User Providers
|--------------------------------------------------------------------------
|
| All authentication drivers have a user provider. This defines how the
| users are actually retrieved out of your database or other storage
| mechanisms used by this application to persist your user's data.
|
| If you have multiple user tables or models you may configure multiple
| sources which represent each model / table. These sources may then
| be assigned to any extra authentication guards you have defined.
|
| Supported: "database", "eloquent"
|
*/
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\Models\User::class,
],
'employees' => [
'driver' => 'eloquent',
'model' => App\Models\Employee::class,
]
],
/*
|--------------------------------------------------------------------------
| Resetting Passwords
|--------------------------------------------------------------------------
|
| You may specify multiple password reset configurations if you have more
| than one user table or model in the application and you want to have
| separate password reset settings based on the specific user types.
|
| The expire time is the number of minutes that the reset token should be
| considered valid. This security feature keeps tokens short-lived so
| they have less time to be guessed. You may change this as needed.
|
*/
'passwords' => [
'users' => [
'provider' => 'users',
'table' => 'password_resets',
'expire' => 60,
'throttle' => 60,
],
],
/*
|--------------------------------------------------------------------------
| Password Confirmation Timeout
|--------------------------------------------------------------------------
|
| Here you may define the amount of seconds before a password confirmation
| times out and the user is prompted to re-enter their password via the
| confirmation screen. By default, the timeout lasts for three hours.
|
*/
'password_timeout' => 10800,
];
view raw config-auth.php hosted with ❤ by GitHub

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 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



use App\Http\Controllers\AuthController;

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


Enter fullscreen mode Exit fullscreen mode

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:



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


Enter fullscreen mode Exit fullscreen mode

E na sequência execute o comando:



php artisan db:seed


Enter fullscreen mode Exit fullscreen mode

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

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 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

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

Top comments (4)

Collapse
 
eufernandodias profile image
Fernando Dias

Opa, tudo bem?
Como implementar mantendo as duas auteticações (web e api)?
Quando eu coloco:
'defaults' => [
'guard' => 'api',
'passwords' => 'company_users',
],

Não consigo mais autenticar via web.

Collapse
 
eufernandodias profile image
Fernando Dias

Acabei descobrindo aqui. Obrigado!

Collapse
 
miguel_souza_70c4a49f3386 profile image
Miguel Souza

opa, tudo bom? Você descobriu como?

Collapse
 
petersonvdf profile image
petersonvdf

Thank you so much