Sử dụng JWT Authentication API trong Laravel 7

Giới thiệu

Trong thời buổi nhà nhà dùng API người người viết API, thì tôi một con người hóng hớt cũng mày mò để thử viết API trên 1 framework khá phổ biến là laravel. Và cũng như đi xe bus thì có ông bán vé kiêm luôn soát vé. Thì API cũng cần 1 ông nào đó để kiểm tra xem bạn đã có vé chưa mà đòi đi xe 😄. Trong bài viết này tôi xin giới thiệu đến 1 ông soát vé tuy lớn tuổi nhưng vẫn làm việc một cách ổn định là JWT (json web token). Do thời lượng chương trình có hạn nên bài viết chỉ có cách ứng dụng jwt vào authen trong laravel (như tên bài viết) chứ không nói về các định nghĩa xem JWT là gì nhé (yaoming).

Install & Config

Điều đầu tiên chúng ta sẽ làm là tạo ra một ứng dụng laravel để thử nghiệm JWT. Nếu bạn có Laravel installer, bạn có thể chạy lệnh sau:

$ laravel new laravel-jwt

Hoặc nếu bạn dùng composer

$ composer global require "laravel/installer"

Tiếp theo là chọn 1 package để hỗ trợ auth 1 cách dễ dàng. Đoạn này giống như chọn ông bán vé xe vậy 😄. Sau 1 cú gg search tôi đã chọn tymon/jwt-auth. Chạy lệnh dưới để install package

$ composer require tymon/jwt-auth:dev-develop --prefer-source

Mở file config/app.php và thêm provider sau vào mảng providers:

Tymon\JWTAuth\Providers\LaravelServiceProvider::class,

Thêm các facades sau vào mảng aliases:

'JWTAuth' => Tymon\JWTAuth\Facades\JWTAuth::class,

'JWTFactory' => Tymon\JWTAuth\Facades\JWTFactory::class,

Tiếp đó, Ta copy file config/jwt.php từ trong vendor sang thư mục app/config :

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

Khi đã xong ta đặt secret jwt-auth bằng cách chạy lệnh sau:

$ php artisan jwt:secret

Ta cần làm cho modal User implement JWT. Mở tệp app / User.phpvà thay thế nội dung bằng:

<?php

    namespace App;

    use Illuminate\Notifications\Notifiable;
    use Illuminate\Foundation\Auth\User as Authenticatable;
    use Tymon\JWTAuth\Contracts\JWTSubject;

    class User extends Authenticatable implements JWTSubject
    {
        use Notifiable;

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

        /**
         * The attributes that should be hidden for arrays.
         *
         * @var array
         */
        protected $hidden = [
            'password', 'remember_token',
        ];

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

Cuối cùng ta đăng kí middleware trong file app/Http/Kernel.php nhé

'auth.jwt' => \Tymon\JWTAuth\Http\Middleware\Authenticate::class, // JWT middleware

Tạo mới Data

Bỏ qua phần config DB trong file.env nhé. Giờ ta sẽ tạo seeder để fake data cho user nhé.

Tạo mới UserSeeder bằng lệnh sau

php artisan make:seeder UserSeeder

Mở file database/seeds/UserSeeder.php và thêm dòng code sau vào function run:

factory(App\User::class, 10)->create();

Ý nghĩa của đoạn này sẽ là tạo 10 record User nhé

Cuối cùng sẽ chạy lệnh run seeder để tạo mới data:

php artisan db:seed --class=UserSeeder

Và giờ, DB đã có data để cho ta test rồi 😄

Tạo mới Controller

Chạy lệnh sau để tạo mới controller

php artisan make:controller APIController

Mở file APIController và sửa lại

<?php

namespace App\Http\Controllers;

use JWTAuth;
use App\User;
use Illuminate\Http\Request;
use Tymon\JWTAuth\Exceptions\JWTException;

class APIController extends Controller
{
    /**
     * @var bool
     */
    public $loginAfterSignUp = true;

    /**
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function login(Request $request)
    {
        $input = $request->only('email', 'password');
        $token = null;

        if (!$token = JWTAuth::attempt($input)) {
            return response()->json([
                'status' => false,
                'message' => 'Invalid Email or Password',
            ], 401);
        }

        return response()->json([
            'status' => true,
            'token' => $token,
        ]);
    }

    /**
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     * @throws \Illuminate\Validation\ValidationException
     */
    public function logout(Request $request)
    {
        $this->validate($request, [
            'token' => 'required'
        ]);

        try {
            JWTAuth::invalidate($request->token);

            return response()->json([
                'status' => true,
                'message' => 'User logged out successfully'
            ]);
        } catch (JWTException $exception) {
            return response()->json([
                'status' => false,
                'message' => 'Sorry, the user cannot be logged out'
            ], 500);
        }
    }
}

Giải thích 1 chút nhé : Trong APIController có 2 fuction là loginlogout . Trong function login thì sử dụng cơ chế Auth của JWTAuth . User sẽ post thông tin gồm email và password. JWTAuth sẽ check nếu thông tin đăng nhập đúng thì sẽ tạo ra 1 token mà thông qua token này ta có thể thao tác với API trong các lần tiếp theo. Trong function logout thì ngược lại kiển tra xem token có hợp lệ không. Nếu đúng thì xóa chúng đi. Nói là xóa nhưng thật ra nó chỉ cho token vào 1 blackList để nếu đã logout ra r thì sẽ không sử dụng được token cũ để thao tác vs API nữa.

Tiếp đó, mình tạo thêm controller để thao tác với User trong DB. Make controller với lệnh sau

php artisan make:controller UserController

Trong file này ta thêm vào function index như sau :

    public function index()
    {
        $users = User::all();

        return response()->json($users, 200);
    }

Tạo mới Router

Mở file routes/api.php và thêm vào các route sau :

Route::post('login', '[email protected]');

Route::group(['middleware' => 'auth.jwt'], function () {
    Route::get('logout', '[email protected]');
    Route::get('users', '[email protected]');
});

Ta có thêm 'middleware' => 'auth.jwt' cho routelogoutusers check xem token đăng nhập có hợp lệ không.

Kết luận

Có câu Có làm thì mới có ăn.., chúng ta đã làm rồi. Và bây giờ là lúc ăn. Mở postman ra và cảm nhận bạn nhớ =)).

Chú ý : Trong postman bạn sử dụng URL là /api/login tương tự với các route khác nhé.