Backend DevelopmentFrontend DevelopmentVueJs Tutorials

Building Ecommerce Website With Lumen Laravel And Nuxtjs 2: JWT Authentication

Building Ecommerce Website With PHP Lumen Laravel And Nuxtjs

In this topic of this series we will implement the Token based authentication known as the JWT authentication in our eCommerce website.

 

 

As we we are dealing with restful apis, session based authentication is not an option to work with, instead token based authentication is the optimal solution where we have a token sent in the form of authorization header that is exchanged across requests.

Open bootstrap/app.php and un-comment those lines:

$app->withFacades();

$app->withEloquent();

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

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

 

Install the JWT package.

In the project root directory open a terminal and run this command:

composer require tymon/jwt-auth

Generate jwt secret key:

php artisan jwt:secret

Next let’s add this line inside the register() method of the AppServiceProvider.

app/Providers/AppServiceProvider.php

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

Next we need to alter the config auth variables to use JWT we can do this in config/auth.php file but unfortunately lumen doesn’t come with config folder in it but you can create the configuration files yourself or copy it from any laravel project.

Let’s create config/auth.php and add the below code:

<?php

return [

    'defaults' => [
        'guard' => env('AUTH_GUARD', 'api'),
        'passwords' => 'users',
    ],

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

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

    'passwords' => [
        //
    ],

];

Then update the User model to implement the JWTSubject contract.

app/Models/User.php

<?php

namespace App\Models;

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

class User extends Model implements JWTSubject, AuthenticatableContract, AuthorizableContract
{
    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',
    ];

    public function products()
    {
        return $this->hasMany(Product::class, 'created_by');
    }

    public function orders()
    {
        return $this->hasMany(Order::class, 'user_id');
    }

    public function shippingAddresses()
    {
        return $this->hasMany(ShippingAddress::class, 'user_id');
    }

    public function shoppingCart()
    {
        return $this->hasMany(ShoppingCart::class, 'user_id');
    }

    public function getJWTIdentifier()
    {
        return $this->getKey();
    }

    public function getJWTCustomClaims()
    {
        return [];
    }


}

In this code i implemented two important methods for JWT which is getJWTIdentifier(), getJWTCustomClaims().

 

 

Login Controller

Create a new directory called Auth/ inside of app/Http/Controllers then create a new laravel controller called LoginController.

app/Http/Controllers/Auth/LoginController.php

<?php


namespace App\Http\Controllers\Auth;


use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Validator;
use Tymon\JWTAuth\JWTAuth;

class LoginController extends Controller
{
    protected $jwt;

    public function __construct(JWTAuth $jwt)
    {
        $this->jwt = $jwt;
    }

    public function login(Request $request)
    {
        $validator = Validator::make($request->only('email', 'password'), [
            'email' => 'required|email',
            'password' => 'required'
        ]);

        if($validator->fails()) {
            return response()->json(['success' => 0, 'message' => 'Please fix these errors', 'errors' => $validator->errors()], 500);
        }

        try {

            $token = $this->jwt->attempt($request->only('email', 'password'));

            if(!$token) {
                return response()->json(['success' => 0, 'message' => 'user not found'], 404);
            }

        } catch (\Tymon\JWTAuth\Exceptions\TokenExpiredException $e) {

            return response()->json(['success' => 0, 'message' => 'token expired'], 500);

        } catch (\Tymon\JWTAuth\Exceptions\TokenInvalidException $e) {

            return response()->json(['success' => 0, 'message' => 'token invalid'], 500);

        } catch (\Tymon\JWTAuth\Exceptions\JWTException $e) {

            return response()->json(['success' => 0, 'message' => 'unknown error'], 500);

        }

        // if everything ok
        $user = Auth::user();

        return response()->json([
            'success' => 1,
            'access_token' => $token,
            'user' => $user
        ]);
    }

    function userDetails()
    {
        $user = Auth::user();

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

    function logout()
    {
        $token = auth()->tokenById(auth()->user()->id);

        $this->jwt->setToken($token)->invalidate();

        \auth()->logout();

        return response()->json([
            'success' => 1,
            'message' => 'Signed out successfully!'
        ]);
    }

    function checkLogin() {
        if(Auth::user()) {
            return response()->json(['success' => 1]);
        }

        return response()->json(['success' => 0]);
    }
}

In this code i injected the JWTAuth contract into the constructor so that i can get access to the helper methods inside of it. In the login() method first i validate for the incoming request data and show error message in case of invalid data.

After validation i called the attempt() method of the JWTAuth instance which return the token if the user credentials is valid. If the operation is successful i return success response along with the token and the user details. This token we will be passed along with any request that requires authorization.

In the logout() method we clear the token from the session and the checkLogin() method used to check if the user is logged in by the Nuxt application as we will see later.

 

Routes

Open routes/web.php and add this code:

$router->group(['prefix' => 'api'], function () use ($router) {
    $router->post('/login', 'Auth\\LoginController@login');

    $router->group(['middleware' => 'auth:api'], function () use ($router) {
        $router->get('/me', 'Auth\\LoginController@userDetails');
        $router->get('/logout', 'Auth\\LoginController@logout');
        $router->get('/check-login', 'Auth\\LoginController@checkLogin');
    });
});

The routes is prefixed by api/ so for example the login route will be api/login. Let’s try this process in postman as shown below:

jwt auth in postman

jwt auth in postman

jwt auth in postman

 

Register Controller

In the same way let’s create a new controller inside of Auth/ directory for user registration.

app/Http/Controllers/Auth/RegisterController

<?php


namespace App\Http\Controllers\Auth;


use App\Http\Controllers\Controller;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
use Tymon\JWTAuth\JWTAuth;

class RegisterController extends Controller
{
    protected $jwt;

    public function __construct(JWTAuth $jwt)
    {
        $this->jwt = $jwt;
    }

    public function register(Request $request)
    {
        $validator = Validator::make($request->only('name', 'email', 'password', 'password_confirmation'), [
            'name' => 'required|string',
            'email' => 'required|email|unique:users',
            'password' => 'required|min:4|confirmed'
        ]);

        if($validator->fails()) {
            return response()->json(['success' => 0, 'message' => 'Please fix these errors', 'errors' => $validator->errors()], 500);
        }

        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();

            $token = auth()->tokenById($user->id);

            return response()->json([
                'success' => 1,
                'message' => 'User Registration success!',
                'access_token' => $token,
                'user' => $user
            ]);

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

Update routes/web.php

$router->group(['prefix' => 'api'], function () use ($router) {
    $router->post('/login', 'Auth\\LoginController@login');
    $router->post('/register', 'Auth\\RegisterController@register');

    $router->group(['middleware' => 'auth:api'], function () use ($router) {
        $router->get('/me', 'Auth\\LoginController@userDetails');
        $router->get('/logout', 'Auth\\LoginController@logout');
        $router->get('/check-login', 'Auth\\LoginController@checkLogin');
    });
});

jwt auth in postman

 

 

Continue to Part3: Preparing admin panel in Nuxtjs

 

What's your reaction?

Excited
0
Happy
0
Not Sure
0
Confused
0

You may also like

Leave a reply

Your email address will not be published. Required fields are marked *