Hướng Dẫn Laravel Sanctum
Laravel Sanctum cung cấp một hệ thống xác thực nhẹ cho SPAs (Single Page Applications), ứng dụng mobile, và các API token-based đơn giản. Nó cho phép mỗi người dùng của ứng dụng tạo nhiều API tokens cho tài khoản của họ.
Tại Sao Chọn Sanctum?
- Đơn giản: Nhẹ hơn và dễ thiết lập hơn nhiều so với Passport.
- Hỗ trợ SPA: Sử dụng các dịch vụ xác thực session dựa trên cookie tích hợp của Laravel cho SPAs.
- API Tokens: Cho phép phát hành API tokens cho người dùng mà không cần sự phức tạp của OAuth2.
Nếu bạn không cần chức năng OAuth2 (như cho phép ứng dụng bên thứ ba kết nối với tài khoản người dùng của bạn), Sanctum thường là lựa chọn tốt hơn Passport.
Bước 1: Cài Đặt
Cài đặt Sanctum qua Composer:
composer require laravel/sanctum
Bước 2: Publish Cấu Hình
Publish các file cấu hình và migration của Sanctum:
php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"
Bước 3: Chạy Migrations
Chạy database migrations để tạo bảng personal_access_tokens:
php artisan migrate
Bước 4: Cấu Hình Middleware
Thêm Sanctum middleware vào nhóm middleware api trong bootstrap/app.php (cho Laravel 11+):
// bootstrap/app.php
use Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful;
->withMiddleware(function (Middleware $middleware) {
$middleware->api(prepend: [
EnsureFrontendRequestsAreStateful::class,
]);
})
Nếu bạn đang sử dụng phiên bản Laravel cũ hơn, thêm vào app/Http/Kernel.php.
Xác Thực API Token
Đây là lựa chọn hoàn hảo cho mobile apps hoặc truy cập API bên ngoài đơn giản.
1. Cập Nhật User Model
Thêm trait HasApiTokens vào model User:
use Laravel\Sanctum\HasApiTokens;
class User extends Authenticatable
{
use HasApiTokens, Notifiable;
}
2. Phát Hành Tokens
Bạn có thể phát hành token trực tiếp từ login controller hoặc command:
$token = $user->createToken('my-device-name');
return ['token' => $token->plainTextToken];
Bạn cũng có thể chỉ định abilities (permissions) cho token:
$token = $user->createToken('token-name', ['server:update'])->plainTextToken;
3. Thu Hồi Tokens
Để logout người dùng hoặc thu hồi access:
// Thu hồi tất cả tokens...
$user->tokens()->delete();
// Thu hồi token đã được sử dụng để xác thực request hiện tại...
$request->user()->currentAccessToken()->delete();
// Thu hồi một token cụ thể...
$user->tokens()->where('id', $tokenId)->delete();
4. Bảo Vệ Routes
Sử dụng middleware auth:sanctum trên các API routes:
Route::middleware('auth:sanctum')->get('/user', function (Request $request) {
return $request->user();
});
5. Kiểm Tra Abilities
Nếu bạn đã sử dụng abilities khi tạo token, bạn có thể kiểm tra chúng:
if ($user->tokenCan('server:update')) {
//
}
Xác Thực SPA
Sanctum thực sự tỏa sáng với SPAs (Vue, React, Angular) được host trên cùng top-level domain. Nó sử dụng cookies thay vì tokens, ngăn các cuộc tấn công XSS đánh cắp tokens từ local storage.
1. Cấu Hình CORS
Đảm bảo config/cors.php cho phép domain SPA của bạn và credentials:
'paths' => ['api/*', 'sanctum/csrf-cookie'],
'allowed_origins' => ['http://localhost:3000'], // URL SPA của bạn
'supports_credentials' => true,
2. Cấu Hình Sanctum State Domains
Trong .env hoặc config/sanctum.php, đặt các domains mà Sanctum nên tin tưởng:
SANCTUM_STATEFUL_DOMAINS=localhost:3000,127.0.0.1:3000
SESSION_DOMAIN=localhost
3. Bảo Vệ Routes
Giống như với API tokens thông thường, bảo vệ routes của bạn với auth:sanctum.
4. Luồng Đăng Nhập
- Bảo vệ CSRF: Đầu tiên, SPA của bạn phải gửi request tới
/sanctum/csrf-cookieđể khởi tạo bảo vệ CSRF. - Đăng nhập: Gửi POST request tới route
/logintiêu chuẩn (sử dụng auth tích hợp của Laravel hoặc Fortify). - Requests: Sau khi đăng nhập, trình duyệt sẽ tự động bao gồm session cookie trong các requests tiếp theo.
Ví dụ với Axios:
axios.defaults.withCredentials = true;
// 1. Lấy CSRF cookie
await axios.get('/sanctum/csrf-cookie');
// 2. Đăng nhập
await axios.post('/login', {
email: 'user@example.com',
password: 'password'
});
// 3. Gửi authenticated request
const response = await axios.get('/api/user');
Testing
Khi test các endpoints được bảo vệ bởi Sanctum, sử dụng helper Sanctum::actingAs:
use Laravel\Sanctum\Sanctum;
public function test_orders_can_be_retrieved()
{
Sanctum::actingAs(
User::factory()->create(),
['view-orders'] // abilities
);
$response = $this->get('/api/orders');
$response->assertOk();
}