Sanctum là một official package. Nó cung cấp trình xác thực đơn giản để phát triển SPA, mobile apps và token-based dành cho APIs.

Giới thiệu

Từ bản Laravel 7.x trở lên, Laravel đã giới thiệu Sanctum là một official package. Sanctum cho phép user tạo nhiều API tokens cho tài khoản của họ. Các tokens này có khả năng chỉ định cá actions và user đó có thể thực hiện khi được sử dụng chúng.

Cách hoạt động

API Tokens

  • Đầu tiên, Sanctum là một package đơn giản, bạn có thể tạo ra các API tokens cho người dùng mà không cần đến sự phức tạp của OAuth. Tính năng này được lấy cảm hứng từ Github và các ứng dụng khác có tính năng “access tokens”. Ví dụ, giả sử trong phần cài đặt của ứng dụng bạn, có màn hình mà user có thể tạo được API token cho tài khoản của họ. Bạn có thể sử dụng Sanctum để tạo và quản lý các tokens này. Những token này có thời hạn rất dài (tính bằng năm), nhưng user có thể hủy bỏ chúng bất cứ khi nào họ muốn.
  • Sanctum cung cấp tính năng này bằng cách lưu trữ API tokens của User trong một bảng CSDL duy nhất và xác thực các request thông qua API token gắn kèm trên Authorization header.

SPA Authentication

  • Thứ 2, Sanctum cung cấp trình xác thực đơn giản cho SPAs (single page applications) cần giao tiếp với API được cung cấp bởi Laravel. Các SPA này có thể tồn tại trong cùng một kho lưu trữ ứng dụng Laravel của bạn hoặc có thể là một kho lưu trữ hoàn toàn riêng biệt, chẳng hạn như SPA được tạo bằng Vue CLI.
  • Sanctum sẽ không sử dụng token trong tính năng này. Thay vào đó, Sanctum sử Laravel’s built-in cookie based session authentication services (trình xác thực phiên dựa trên cookie được tích hợp sẵn). Điều này cung cấp các lợi ích của CSRF protection, session authentication, cũng như bảo vệ chống rò rỉ thông tin xác thực qua XSS. Sanctum sẽ chỉ cố gắng xác thực bằng cookie khi request bắt nguồn từ giao diện người dùng SPA của bạn.

Cài đặt

Yêu cầu

  • Laravel 7.x trở lên
  • Composer
  • Postman

Phiên bản mới đây của Laravel đã tích hợp sẵn Laravel Sanctum. Tuy nhiên, nếu trong file composer.json của bạn chưa được khai báo laravel/sanctum, bạn có thể tiến hành cài đặt theo các bước dưới đây.

Bạn có thể cài Laravel sanctum thông qua trình quản lý package Composer:

composer require laravel/sanctum

Tiếp theo, bạn nên publish file config và file migrate bằng lệnh command:

php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"

Cuối cùng, bạn chạy migrate. Sanctum sẽ tạo một bảng để lưu trữ API tokens:

php artisan migrate

Cấu hình

Overriding model PersonalAccessToken

Mặc dù sự thay đổi này là không bắt buộc và đôi khi không cần thiết phải làm điều đó thì ứng dụng của ta vẫn có thể hoạt động tốt.

use Laravel\Sanctum\PersonalAccessToken as SanctumPersonalAccessToken;

class PersonalAccessToken extends SanctumPersonalAccessToken
{
    // ...
}

Sau đó bạn cần cập nhật lại Sanctum sử dụng model bạn vừa custom lại thông qua phương thức usePersonalAccessTokenModel của Sanctum. Sau cùng, bạn nên gọi phương thức này vào hàm boot vào 1 service provider bất kì.

use App\Models\Sanctum\PersonalAccessToken;
use Laravel\Sanctum\Sanctum;

/**
 * Bootstrap any application services.
 *
 * @return void
 */
public function boot()
{
    Sanctum::usePersonalAccessTokenModel(PersonalAccessToken::class);
}

API token Authentication (dùng trong xác thực api)

Tạo API Tokens

Sanctum cho phép bạn tạo API tokens / personal access tokens và dùng nó để xác thực request đến ứng dụng của bạn. Khi gửi request sử dụng tới token, thì token sẽ được gắn kèm trên Authorization header.

Để bắt đầu khởi tạo token cho users, hãy thêm HasApiTokens cho model mà bạn muốn (ở đây mình sử dụng model User).

use Laravel\Sanctum\HasApiTokens;

class User extends Authenticatable
{
    use HasFactory, Notifiable, HasApiTokens;
    ...
}

Sanctum tạo API tokens bằng method createToken. Chúng sẽ được hash bằng hàm SHA-256 trước khi lưu vào database và chúng ta có thể lấy ra sử dụng thông qua property plainTextToken

$token = $user->createToken('token-name');

return $token->plainTextToken;

Việc tạo API tokens tất nhiên dùng để đăng nhập ròi, ta khai báo controller để handle:

namespace App\Http\Controllers;

use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;

class AuthController extends Controller
{
    public function login(Request $request)
    {
        $request->validate([
            'email' => 'email|required',
            'password' => 'required'
        ]);

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

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

        $user = User::where('email', $request->email)->first();

        if (!Hash::check($request->password, $user->password, [])) {
            throw new \Exception('Error in Login');
        }

        $tokenResult = $user->createToken('authToken')->plainTextToken;

        return response()->json([
            'status_code' => 200,
            'access_token' => $tokenResult,
            'token_type' => 'Bearer',
        ]);
    }
}

Đừng quên khai báo Route login trong file routes/api.php

Route::middleware('auth:sanctum')
    ->get('/user', function (Request $request) {
    return $request->user();
});

Route::post('login', [AuthController::class, 'login']);

Nhanh tay mở Postman lên và kiểm tra api vừa viết nó chạy như thế nào. Trước tiên chạy seed để tạo một số user mẫu nha.
Mở file database/seeders/DatabaseSeeder.php

public function run()
{
    \App\Models\User::factory(10)->create();
}

Chạy command:

 php artisan db:seed

Mở postman lên và thử login xem thế nào

Một tips nhỏ khi sử dụng postman giúp ta đỡ phải copy token khi sử dụng cho những api khác:

api: http://127.0.0.1:8000/api

Lấy thông tin user

Chúng ta cũng có thể thu hồi những token bằng cách xóa trong database nhưng tất nhiên là sử dụng method có sẵn:

// Revoke all tokens...
$user->tokens()->delete();

// Revoke the user's current token...
$request->user()->currentAccessToken()->delete();    

// Revoke a specific token...
$user->tokens()->where('id', $id)->delete();

Phân quyền

Mặc định khi tạo token thì nó có thể xác thực tất cả các route yêu cầu token.
Nhưng bạn có nhu cầu cấp token sử dụng cho một số “phạm vi” quy định sẵn. Bạn có thể truyền một mảng abilities làm đối số thứ 2 cho phương thức createToken:

$tokenResult = $user->createToken('authToken', ['server:update'])->plainTextToken;

Khi xử lý xác thực một request và kiểm tra token có quyền truy cập hay không thì bạn sử dụng tokenCan để kiểm tra nó:

if ($user->tokenCan('server:update')) {
    //
}

Bạn có thể tạo middleware và khai báo nó sau middleware auth:sanctum

Kết luận

Trên đây mình đã giới thiệu cũng như demo về Laravel Sanctum dùng để xác thực cũng như là phân quyền trong việc xây dựng API. Hy vọng bài viết sẽ giúp ích cho các bạn trong quá trình học tập và làm việc.

Nguồn tham khảo:

Rất mong được sự ủng hộ của mọi người để mình có động lực ra những bài viết tiếp theo.
{\__/}
( ~.~ )
/ > ♥️ I LOVE YOU 3000

JUST DO IT!