JWT Authenticated API with Lumen

Pré requisitos

Tenha o projeto lumen instalado dentro do Laradock.

E já funcionando no localhost. (como na imagem abaixo)

Instalação

Crie um arquivo .env, copie todo o conteúdo em .env.example no arquivo .env e adicione suas configurações de banco de dados.

Em boostrap/app.php descomentar as fachadas e o método eloquente.

//before

// $app->withFacades();

// $app->withEloquent();

//after

$app->withFacades();

$app->withEloquent();

Criação da tabela de usuários

Crie a migration do bando de dados com o seguinte comando:

php artisan make:migration create_users_table --create=users

Localize o arquivo de migração database/migrations/*_create_users_table.php e adicione colunas da tabela de necessidade (nome, email, senha); veja o código abaixo:

...
    public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->string('name');
            $table->string('email')->unique()->notNullable();
            $table->string('password');
            $table->timestamps();
        });
    }
...

Execute a migração do banco de dados.

php artisan migrate

Adicionar rota de registro que, como o nome indica; registrar usuários. Localize routes/web.php e insira o código necessário, como visto abaixo:

// API route group
$router->group(['prefix' => 'api'], function () use ($router) {
   // Matches "/api/register
   $router->post('register', 'AuthController@register');

});

Como vamos usar o prefixo em todos os pontos de extremidade, para não causar repetição de cṍdigo, usaremos o agrupamento de rotas para fazer exatamente isso.

Este método ($router->post($uri, $callback); recebe um parâmetro url e callback. No campo $callback, AuthController é a classe do Controller (criaremos essa classe daqui a pouco) e register é um método nessa classe.

Vamos criar nosso AuthControler.

Crie um arquivo app/Http/Controllers/AuthController.php e preencha-o com o código conforme mostrado abaixo.

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use  App\User;

class AuthController extends Controller
{
    /**
     * Store a new user.
     *
     * @param  Request  $request
     * @return Response
     */
    public function register(Request $request)
    {
        //validate incoming request
        $this->validate($request, [
            'name' => 'required|string',
            'email' => 'required|email|unique:users',
            'password' => 'required|confirmed',
        ]);

        try {

            $user = new User;
            $user->name = $request->input('name');
            $user->email = $request->input('email');
            $plainPassword = $request->input('password');
            $user->password = app('hash')->make($plainPassword);

            $user->save();

            //return successful response
            return response()->json(['user' => $user, 'message' => 'CREATED'], 201);

        } catch (\Exception $e) {
            //return error message
            return response()->json(['message' => 'User Registration Failed!'], 409);
        }

    }

}

Registre um usuário (use POSTMAN) com a rota localhost:8000/api/register e você deverá obter uma resposta bem-sucedida como esta:

Instalação do pacote de autenticação JWT

composer require tymon/jwt-auth

Agora adicione o seguinte snippet ao bootstrap/app.php arquivo na seção provedores da seguinte maneira:

// Descomente está linha
$app->register(App\Providers\AuthServiceProvider::class);

// Adicione está linha
$app->register(Tymon\JWTAuth\Providers\LumenServiceProvider::class);

Em seguida, descomente o authmiddleware no mesmo arquivo:

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

Fazendo isso é incluido um comando auxiliar para gerar uma chave.

php artisan jwt:secret

Crie um arquivo config/auth.php com a configuração abaixo:

//config.auth.php

<?php

return [
    'defaults' => [
        'guard' => 'api',
        'passwords' => 'users',
    ],

    'guards' => [
        'api' => [
            'driver' => 'jwt',
            'provider' => 'users',
        ],
    ],

    'providers' => [
        'users' => [
            'driver' => 'eloquent',
            'model' => \App\User::class
        ]
    ]
];

Faça algumas alterações no seu User model (app/User.php) para atender aos requisitos do tymon / jwt-auth. Fique de olho em tudo o que inclui "JWT".

<?php

namespace App;

use Illuminate\Auth\Authenticatable;
use Laravel\Lumen\Auth\Authorizable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;


use Tymon\JWTAuth\Contracts\JWTSubject;

class User extends Model implements AuthenticatableContract, AuthorizableContract, JWTSubject
{
    use Authenticatable, Authorizable;

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'name', 'email'
    ];

    /**
     * The attributes excluded from the model's JSON form.
     *
     * @var array
     */
    protected $hidden = [
        'password',
    ];




    /**
     * 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 [];
    }
}

Adicionar rota de login em routes/web.php:

// API route group
$router->group(['prefix' => 'api'], function () use ($router) {
     // Matches "/api/register
    $router->post('register', 'AuthController@register');

      // Matches "/api/login
     $router->post('login', 'AuthController@login');
});

Adicione um método global respondWithToken à classe Controller em app/Http/Controllers/Controller.php. Isso é para que possamos acessá-lo de qualquer outro controlador.

    ...
    //import auth facades
    use Illuminate\Support\Facades\Auth;


    //Add this method to the Controller class
    protected function respondWithToken($token)
    {
        return response()->json([
            'token' => $token,
            'token_type' => 'bearer',
            'expires_in' => Auth::factory()->getTTL() * 60
        ], 200);
    }

Adicione um método de login à sua classe AuthController em app/Http/Controllers/AuthController.php.

 ...

   //import auth facades
   use Illuminate\Support\Facades\Auth;

   ...

     /**
     * Get a JWT via given credentials.
     *
     * @param  Request  $request
     * @return Response
     */
    public function login(Request $request)
    {
          //validate incoming request
        $this->validate($request, [
            'email' => 'required|string',
            'password' => 'required|string',
        ]);

        $credentials = $request->only(['email', 'password']);

        if (! $token = Auth::attempt($credentials)) {
            return response()->json(['message' => 'Unauthorized'], 401);
        }

        return $this->respondWithToken($token);
    }

Faça login em um usuário que você cadastrou na rota localhost:8000/api/login e você deverá obter uma resposta bem-sucedida, como:

Rotas autenticadas

Para a nossa grande final, vamos fazer algumas rotas autenticadas.

Adicione algumas rotas para routes/web.php

...
// API route group
$router->group(['prefix' => 'api'], function () use ($router) {
    // Matches "/api/register
   $router->post('register', 'AuthController@register');
     // Matches "/api/login
    $router->post('login', 'AuthController@login');

    // Matches "/api/profile
    $router->get('profile', 'UserController@profile');

    // Matches "/api/users/1
    //get one user by id
    $router->get('users/{id}', 'UserController@singleUser');

    // Matches "/api/users
    $router->get('users', 'UserController@allUsers');
});

...

Crie um arquivo app/Http/Controllers/UserController.php e preencha-o com este código de aparência elegante.

<?php

namespace App\Http\Controllers;

use Illuminate\Support\Facades\Auth;
use  App\User;

class UserController extends Controller
{
     /**
     * Instantiate a new UserController instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->middleware('auth');
    }

    /**
     * Get the authenticated User.
     *
     * @return Response
     */
    public function profile()
    {
        return response()->json(['user' => Auth::user()], 200);
    }

    /**
     * Get all User.
     *
     * @return Response
     */
    public function allUsers()
    {
         return response()->json(['users' =>  User::all()], 200);
    }

    /**
     * Get one user.
     *
     * @return Response
     */
    public function singleUser($id)
    {
        try {
            $user = User::findOrFail($id);

            return response()->json(['user' => $user], 200);

        } catch (\Exception $e) {

            return response()->json(['message' => 'user not found!'], 404);
        }

    }

}

Abaixo está um exemplo de chamada para um dos três pontos de extremidade adicionados recentemente

O fim-ish!

Espero que este artigo tenha ajudado você de alguma forma e que você desenvolva esse conhecimento para implantar APIs impressionantes em um futuro próximo.

Até mais. 😃

Referências

https://dev.to/ndiecodes/build-a-jwt-authenticated-api-with-lumen-2afm

https://jwt-auth.readthedocs.io/en/develop/lumen-installation/

Last Updated:
Contributors: Maicon Cerutti