Authentication Json Web Token (JWT) to Laravel 8

Hôm nay mình chia sẻ với mọi người cách tích hợp xác thực Authentication Json Web Token (JWT) to Laravel 8. Đầu tiên bạn vào đường dẫn sau để download hoặc git clone source về máy tính nhé : https://github.com/laravel/laravel/tree/8.x

Sau khi tải về bạn tiến hành giải nén và cd tới thư mục project chạy lệnh: composer install  để cài các thư viện cần thiết của laravel, bạn sẽ thấy được thư mục vendor

Okay giờ hãy tạo một cơ sở dữ liệu database, nếu bạn đã có sẵn thì tiến hành mở file .env lên chỉnh sửa connect tới database của bạn

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=jwt
DB_USERNAME=root
DB_PASSWORD=MẬT_KHẨU_MYSQL

Tiến hành chạy câu lệnh: php artisan migrate 

Laravel sẽ tạo các table cần thiết đến database của bạn, bạn có thể vào database xem thử nhé

# Cài đặt cấu hình JWT trong laravel bằng câu lệnh sau:

composer require tymon/jwt-auth:^1.0.2

Authentication Json Web Token (JWT) to Laravel 8

Sau khi cài đặt thành công! tiếp theo ta cần phải tích hợp một số code đến file config/app.php

'providers' => [
    ....
    ....
    Tymon\JWTAuth\Providers\LaravelServiceProvider::class,
],

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

'aliases' => [
    ....
    'JWTAuth' => Tymon\JWTAuth\Facades\JWTAuth::class,
    'JWTFactory' => Tymon\JWTAuth\Facades\JWTFactory::class,
    ....
],

Tiếp đó, sử dụng lệnh sau để public các file JWT Auth từ trong vendor sang config/jwt.php:

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

Authentication Json Web Token (JWT) to Laravel 8

Tiếp theo là việc tạo mã khóa bí mật của ta thôi, nó là mã khóa secret key

php artisan jwt:secret

Authentication Json Web Token (JWT) to Laravel 8

Bạn sẽ thấy một secret key được tạo trong file .env

* Thiết lập Model User

Các bạn mở file App\Models\User.php lên và implement interface Tymon\JWTAuth\Contracts\JWTSubject; thư viện này vào nhé

<?php

namespace App\Models;

use Illuminate\Notifications\Notifiable;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Tymon\JWTAuth\Contracts\JWTSubject;

class User extends Authenticatable implements JWTSubject
{
    use HasFactory, 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',
    ];

    /**
     * The attributes that should be cast to native types.
     *
     * @var array
     */
    protected $casts = [
        'email_verified_at' => 'datetime',
    ];

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

Các bạn chú ý ở mình Class User mình có  implements JWTSubject, đồng thời mình thêm 2 function này(getJWTCustomClaims,getJWTIdentifier)

# Thiết lập JWT Auth Guard để bảo vệ quá trình xác thực của ứng dụng Laravel

Hãy mở file config/auth.php lên và chỉnh sửa như sau:

 /*
    |--------------------------------------------------------------------------
    | Authentication Defaults
 
    */

    'defaults' => [
        'guard' => 'api',//default "web"
        'passwords' => 'users',
    ],

    /*
    |--------------------------------------------------------------------------
    | Authentication Guards

    |
    */

    'guards' => [
        'web' => [
            'driver' => 'session',
            'provider' => 'users',
        ],
        'api' => [
            'driver' => 'jwt',  //default "token"
            'provider' => 'users',
            'hash' => false,
        ],
    ],

 

# Tạo Controller đễ xác thực người dùng :

Bạn chạy câu lệnh dưới sẽ được một file AuthController.php trong thư mục App\Controllers\Api

php artisan make:controller Api/AuthController

Bạn mở file lên và viết các phương thức Login,Register, Refetch Token, ChangePassword,....

<?php

namespace App\Http\Controllers\Api;
use Illuminate\Http\Request;

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


class AuthController extends Controller
{
    /**
     * Create a new AuthController instance.
     *
     * @return void
     */
    public function __construct() {
        $this->middleware('auth:api', ['except' => ['login', 'register']]);
     
    }

    /**
     * Get a JWT via given credentials.
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function login(Request $request){
    	$validator = Validator::make($request->all(), [
            'email' => 'required|email',
            'password' => 'required|string|min:6',
        ]);

        if ($validator->fails()) {
            return response()->json($validator->errors(), 422);
        }

        if (! $token = auth('api')->attempt($validator->validated())) {
            return response()->json(['error' => 'Unauthorized'], 401);
        }

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

    /**
     * Register a User.
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function register(Request $request) {
        $validator = Validator::make($request->all(), [
            'name' => 'required|string|between:2,100',
            'email' => 'required|string|email|max:100|unique:users',
            'password' => 'required|string|confirmed|min:6',
        ]);

        if($validator->fails()){
            return response()->json($validator->errors()->toJson(), 400);
        }

        $user = User::create(array_merge(
                    $validator->validated(),
                    ['password' => bcrypt($request->password)]
                ));

        return response()->json([
            'message' => 'User successfully registered',
            'user' => $user
        ], 201);
    }


    /**
     * Log the user out (Invalidate the token).
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function logout() {
        auth('api')->logout();

        return response()->json(['message' => 'User successfully signed out']);
    }

    /**
     * Refresh a token.
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function refresh() {
        return $this->createNewToken(auth('api')->refresh());
    }

    /**
     * Get the authenticated User.
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function userProfile() {
        return response()->json(auth('api')->user());
    }

    /**
     * Get the token array structure.
     *
     * @param  string $token
     *
     * @return \Illuminate\Http\JsonResponse
     */
    protected function createNewToken($token){
        return response()->json([
            'access_token' => $token,
            'token_type' => 'bearer',
            'expires_in' => auth('api')->factory()->getTTL() * 60,
            'user' =>auth('api')->user()
        ]);
    }

    public function changePassWord(Request $request) {
        $validator = Validator::make($request->all(), [
            'old_password' => 'required|string|min:6',
            'new_password' => 'required|string|confirmed|min:6',
        ]);

        if($validator->fails()){
            return response()->json($validator->errors()->toJson(), 400);
        }
        $userId =auth('api')->user()->id;

        $user = User::where('id', $userId)->update(
                    ['password' => bcrypt($request->new_password)]
                );

        return response()->json([
            'message' => 'User successfully changed password',
            'user' => $user,
        ], 201);
    }
}

Okay mình sẽ giải thích sơ qua cho mọi người hiểu cơ chế xử lý nó như thế nào nhé

1. Đăng ký user ta cần khi báo 4 tham số (name,email,password, password_confirmation)

2. Login ta cần 2 tham số(email,password), nếu login thành công ta sẽ được một access_token

3. Lấy access_token đó gắn vào header Bearer token để ta có thể lấy thông tin user

4. Nếu access_token hết hạn, ta cần gửi access_token đến server để tạo lại token mới cho ta (nhớ là phải gắn nó vào header bearer token nhé)

5. Logout ta cũng như bước 2,3 cũng kèm access_token đó trong header bearer token

6. Change password ta cần gửi 3 tham số (email, old_password, new_password, new_password_confirmation) , đồng thời cũng kèm access_token đến trong header nhé

# Thiết lập Route

Hãy mời routes/api.php 

Route::group([
    'middleware' => 'api',
    'namespace' => 'App\Http\Controllers',
    'prefix' => 'auth'

], function ($router) {
    Route::post('/login', 'Api\AuthController@login');
    Route::post('/register','Api\AuthController@register');
    Route::post('/logout', 'Api\AuthController@logout');
    Route::post('/refresh', 'Api\AuthController@refresh');
    Route::get('/user-profile','Api\AuthController@userProfile');
    Route::post('/change-pass', 'Api\AuthController@changePassWord');    
});

Giờ chúng ta thực hành thôi, nảy giờ làm từa lưa hết rồi, không biết có chạy không kaka, run server thôi: php artisan serve

Hình 1: Register

Authentication Json Web Token (JWT) to Laravel 8

 

Hình 2: Login

Authentication Json Web Token (JWT) to Laravel 8

Hình 3: get thông tin user, chúng ta cần lấy access_token trả về khi login, gắn vào header bearer token để lấy thông tin người dùng

Authentication Json Web Token (JWT) to Laravel 8

 

Hình 4: Logout token, chúng ta cần lấy access_token trước đó gắn trong header bearer token. Để xử lý logout

Authentication Json Web Token (JWT) to Laravel 8

 

Hình 5: Giả sử bạn chưa logout, bạn dẫn còn access_token mà nó đã hết hạn, thì bạn có thể gắn refresh token , để createToken mới về cho ta, cách làm cũng như các bước trên, gắn token vào header bearer token 

Authentication Json Web Token (JWT) to Laravel 8

Hình 6: Lấy access_token gắn vào header bearer token để cập nhật password nhé :

Authentication Json Web Token (JWT) to Laravel 8

Okay vậy là xong , các bạn có thể thực hành thử nhé. ở đây mình chia sẻ một số kinh nghiệm khi gặp phải như sau:

- Giả sử web bạn đã cài đặt php artisan make:auth rồi, giờ bạn muốn gắn jwt nửa, bạn sẽ gặp một lỗi là sử dụng login auth trên web không được, mà login jwt api trên postman thì ok. 

- Chính vì trong Auth nó cũng sử dụng auth()->user() nó đụng với jwt mà bạn thấy người ta thường cài đặt auth()->user() nửa

- Chính vì thế mà bạn có thể xem lại đoạn code bên trên của mình có chỉ định rõ gàn cho auth('api')->user() trong file AuthController. Để tránh ảnh hưởng xung đột lẫn nhau

Thì lúc này bạn đã có thể vừa sử dụng được login auth trên web và sử dụng jwt api bên postman

Nói chung hơi lu bu, Mình cũng mới gặp phải, nên chia sẻ với mọi người, nếu mọi người gặp phải thì xử lý vụ đó thử xem nhé!

 

Bài Viết Liên Quan

Messsage

Nếu bạn thích chia sẻ của tôi, đừng quên nhấn nút !ĐĂNG KÝ