JWT & Laravel: Mở Khóa Bảo Mật API Bằng Chiếc Vé Vàng
Lavarel

JWT & Laravel: Mở Khóa Bảo Mật API Bằng Chiếc Vé Vàng

Author

Admin System

@root

Ngày xuất bản

19 Mar, 2026

Lượt xem

1 Lượt

JWT_Authentication

Hôm nay, Creyt sẽ cùng các bạn 'mổ xẻ' một trong những khái niệm 'hot' nhất nhì làng lập trình: JWT Authentication, đặc biệt là khi nó 'cặp kè' với Laravel. Tưởng tượng thế này, bạn có một ngôi nhà với bao nhiêu báu vật (API dữ liệu quan trọng). Hồi xưa, mỗi lần muốn vào nhà, bạn phải gọi điện cho bảo vệ (server) và ông ấy phải chạy đi tìm danh sách khách quen để kiểm tra (stateless vs stateful). Mất thời gian đúng không? JWT chính là chiếc 'vé vàng' thần kỳ, một khi bạn có nó, bạn cứ thế mà vào, bảo vệ chỉ cần liếc mắt một cái là biết vé thật hay giả, không cần lật sổ sách nữa.

1. JWT là gì? Chiếc Vé Thần Kỳ Có Cấu Trúc Ra Sao?

Vậy, cái 'vé vàng' JWT (JSON Web Token) này là gì? Đơn giản nó là một chuỗi ký tự dài ngoằng nhưng chứa đựng đủ thông tin để chứng minh bạn là ai và bạn được phép làm gì. Nó giống như một tấm chứng minh thư điện tử được đóng dấu niêm phong vậy. JWT có ba phần chính, ngăn cách bởi dấu chấm (.), đọc từ trái sang phải:

  • Header (Tiêu đề): Giống như bìa sách, nó cho biết loại token là gì (thường là JWT) và thuật toán mã hóa (ví dụ: HS256) được dùng để 'niêm phong'.
  • Payload (Tải trọng): Đây là phần 'ruột' chứa thông tin quan trọng về người dùng (ví dụ: ID, tên, vai trò) và các thông tin khác như thời gian hết hạn của token. Đừng bao giờ bỏ mật khẩu vào đây nhé, đây là phần có thể đọc được!
  • Signature (Chữ ký): Đây là 'con dấu niêm phong' thần thánh. Nó được tạo ra bằng cách lấy Header, Payload và một 'bí mật' (secret key) chỉ server biết, rồi dùng thuật toán mã hóa. Cái này đảm bảo token không bị giả mạo. Nếu ai đó cố tình sửa Header hoặc Payload, chữ ký sẽ không khớp và token sẽ bị từ chối ngay lập tức.

2. Tại Sao JWT Lại "Hot" Đến Vậy? Lợi Ích Không Tưởng

Tại sao JWT lại được giới API 'cưng chiều' đến vậy?

  • Stateless (Không trạng thái): Server không cần lưu trữ thông tin session của bạn. Mỗi request đều mang theo token, server chỉ cần xác minh chữ ký là xong. Giúp server 'nhẹ gánh' hơn, dễ dàng mở rộng (scale) hơn.
  • Cross-domain/Microservices: Rất lý tưởng cho các kiến trúc microservices hoặc khi bạn có nhiều ứng dụng (web, mobile) cùng dùng chung một API. Một token có thể dùng cho nhiều dịch vụ.
  • Mobile-Friendly: Dễ dàng tích hợp vào các ứng dụng di động vì nó không dựa vào cookie hay session truyền thống.
Illustration

3. Hòa Nhập Cùng Laravel: 'Trợ Thủ' Đắc Lực tymon/jwt-auth

Giờ đến phần 'thực chiến' với Laravel. Laravel là một framework 'hảo hán' nhưng nó sinh ra đã có cơ chế session-based authentication truyền thống. Để dùng JWT, chúng ta cần một 'trợ thủ đắc lực'. Gói tymon/jwt-auth chính là người hùng đó. Nó giúp chúng ta dễ dàng tích hợp JWT vào hệ thống Laravel, biến việc cấp phát và xác thực 'vé vàng' trở nên đơn giản như ăn kẹo.

Cài đặt và Cấu hình

Để bắt đầu, hãy cùng 'phù phép' cho dự án Laravel của bạn:

  1. Cài đặt gói tymon/jwt-auth:
    composer require tymon/jwt-auth
    
  2. Xuất bản cấu hình:
    php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider"
    
    Lệnh này sẽ tạo file config/jwt.php. Đây là nơi bạn có thể tùy chỉnh mọi thứ về JWT của mình.
  3. Tạo khóa bí mật (Secret Key): Đây là 'bí mật' mà server dùng để ký token. Tuyệt đối không để lộ!
    php artisan jwt:secret
    
    Lệnh này sẽ thêm JWT_SECRET vào file .env của bạn.

Chuẩn bị User Model

Model User của bạn cần biết cách hoạt động với JWT. Nó cần implement interface Tymon\JWTAuth\Contracts\JWTSubject.

// app/Models/User.php
<?php

namespace App\Models;

use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;
use Tymon\JWTAuth\Contracts\JWTSubject; // Thêm dòng này

class User extends Authenticatable implements JWTSubject // Thêm implements JWTSubject
{
    use HasApiTokens, HasFactory, Notifiable;

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

    /**
     * The attributes that should be hidden for serialization.
     *
     * @var array<int, string>
     */
    protected $hidden = [
        'password',
        'remember_token',
    ];

    /**
     * The attributes that should be cast.
     *
     * @var array<string, string>
     */
    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 [];
    }
}

getJWTIdentifier() trả về ID của người dùng, dùng làm chủ thể của token. getJWTCustomClaims() cho phép bạn thêm các thông tin tùy chỉnh vào payload nếu cần (ví dụ: vai trò của người dùng).

4. Code Minh Họa: Cấp Phát và Sử Dụng "Vé Vàng"

Giờ là lúc 'trình diễn' cách cấp 'vé vàng' khi người dùng đăng nhập.

Controller Đăng nhập

Chúng ta sẽ tạo một AuthController để xử lý việc đăng nhập, đăng xuất, làm mới token và lấy thông tin người dùng.

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Tymon\JWTAuth\Facades\JWTAuth;

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

    /**
     * Get a JWT via given credentials.
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function login(Request $request)
    {
        $credentials = $request->only('email', 'password');

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

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

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

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

        return response()->json(['message' => 'Successfully logged out']);
    }

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

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

Và đừng quên định nghĩa các route cho nó trong routes/api.php:

// routes/api.php
Route::group([
    'middleware' => 'api',
    'prefix' => 'auth'
], function ($router) {
    Route::post('login', [App\Http\Controllers\AuthController::class, 'login']);
    Route::post('logout', [App\Http\Controllers\AuthController::class, 'logout']);
    Route::post('refresh', [App\Http\Controllers\AuthController::class, 'refresh']);
    Route::post('me', [App\Http\Controllers\AuthController::class, 'me']); // Protected route example
});

Khi người dùng gửi email và password đến route /api/auth/login, nếu thông tin hợp lệ, server sẽ cấp cho họ một access_token – chính là 'vé vàng' đó. Các request sau đó, người dùng chỉ cần đính kèm token này vào header Authorization: Bearer <token> là có thể truy cập các route được bảo vệ.

Bảo vệ Route với Middleware

Để bảo vệ các route, chúng ta dùng middleware auth:apitymon/jwt-auth đã cung cấp sẵn.

// Trong file routes/api.php, ví dụ cho route 'me' ở trên
Route::post('me', [App\Http\Controllers\AuthController::class, 'me'])->middleware('auth:api');

// Hoặc áp dụng cho một nhóm route
Route::group(['middleware' => ['auth:api']], function () {
    Route::get('/orders', [OrderController::class, 'index']);
    Route::post('/products', [ProductController::class, 'store']);
});

Middleware này sẽ kiểm tra xem token có hợp lệ không, đã hết hạn chưa, và nếu mọi thứ 'ổn áp', nó sẽ gán thông tin người dùng vào auth()->user(), cho phép request tiếp tục.

5. Mẹo Vặt "Thực Chiến" và Best Practices

Để sử dụng 'vé vàng' JWT một cách thông minh và an toàn, nhớ vài 'mẹo vặt' sau nhé:

  • Thời gian hết hạn (Expiration Time - exp): Đừng bao giờ cấp một chiếc vé 'vô thời hạn'. Token nên có thời gian hết hạn ngắn (ví dụ: 15-60 phút). Điều này giảm thiểu rủi ro nếu token bị đánh cắp.
  • Refresh Token: Khi access_token hết hạn, thay vì bắt người dùng đăng nhập lại, bạn có thể cấp một refresh_token dài hạn hơn. refresh_token này dùng để đổi lấy access_token mới. refresh_token nên được lưu trữ cẩn thận hơn (ví dụ: trong http-only cookie) và chỉ được gửi một lần duy nhất để đổi token mới.
  • Lưu trữ Token an toàn: Tuyệt đối không lưu token vào localStorage trên trình duyệt vì nó dễ bị tấn công XSS. sessionStorage hoặc http-only cookies là lựa chọn tốt hơn cho access_token. Với refresh_token, http-only cookie là best practice.
  • Luôn dùng HTTPS: Mọi giao tiếp giữa client và server phải qua HTTPS để mã hóa dữ liệu, ngăn chặn kẻ xấu 'nghe lén' và lấy cắp token.
  • Revocation (Hủy bỏ): Mặc dù JWT là stateless, nhưng đôi khi bạn cần khả năng hủy bỏ một token (ví dụ: khi người dùng đổi mật khẩu hoặc bị phát hiện hành vi đáng ngờ). Bạn có thể duy trì một danh sách đen (blacklist) các token đã bị hủy trên server, hoặc thay đổi JWT_SECRET để vô hiệu hóa tất cả token cũ.

6. Ứng Dụng Thực Tế: JWT Hiện Diện Ở Đâu?

Vậy, 'vé vàng' JWT này được dùng ở đâu trong thế giới thực?

  • Single Page Applications (SPAs): Các ứng dụng như React, Angular, Vue.js thường dùng JWT để xác thực người dùng với backend API.
  • Mobile Applications: Ứng dụng iOS và Android cũng là 'fan cứng' của JWT vì sự tiện lợi và không trạng thái của nó.
  • Microservices Architectures: Trong các hệ thống lớn với nhiều dịch vụ nhỏ giao tiếp với nhau, JWT là một cách tuyệt vời để xác thực chéo giữa các dịch vụ mà không cần chia sẻ trạng thái.
  • API Gateways: Cổng API có thể xác thực JWT một lần duy nhất trước khi chuyển request đến các dịch vụ backend.

Lời Kết của Giảng viên Creyt

Đó, các bạn thấy đấy, JWT Authentication không chỉ là một khái niệm 'thời thượng' mà còn là một công cụ cực kỳ mạnh mẽ và linh hoạt để bảo vệ API của bạn, đặc biệt là khi kết hợp với sự 'mát tay' của Laravel. Hãy nắm vững nó, và bạn đã có thêm một 'siêu năng lực' trong hành trình xây dựng các ứng dụng web hiện đại rồi đấy! Chúc các bạn 'code' vui vẻ và an toàn!

Thuộc Series: Lavarel

Bài giảng này được tự động xuất bản ngẫu nhiên từ thư viện kiến thức. Đừng quên đón xem các Từ khoá Hướng Dẫn tiếp theo nhé!

#tech #cyberpunk #laravel
Chỉnh sửa bài viết

Bình luận (0)

Vui lòng Đăng Nhập để Bình luận

Hỗ trợ Markdown cơ bản
Nguyễn Văn A
1 ngày trước

Tính năng này đỉnh quá ad ơi, chờ mãi mới thấy một blog Tiếng Việt có UI/UX xịn như vầy!