زمانی که در حال توسعه یک API با لاراول هستید، یکی از قسمتهای مهم احراز هویت (Authentication) است. احراز هویت در API به طور خلاصه باید به صورتی توسعه داده شود، که در زمان درخواست از سمت Client به Server، یک مشخصه برای سرور ارسال شود، تا بتواند تشخیص دهد، که آیا کاربر مورد نظر احراز شده است، یا خیر که بتواند، جوابی را به Client ارسال کند. در این مقاله به بررسی احراز هویت با API در لاراول میپردازیم.
خروجی را برای درخواستهای بعد باید در Header درخواست خود، وارد کنید.
در صورتی که توکن را وارد نکنید با خطای 401 (Unautheticated) برمیخورید. و در صورت وارد کردن اطلاعات به شما نمایش داده میشود.
برای اضافه کردن توکن در Header درخواست، در فریم ورکهای جاوا اسکریپت یا اجرای درخواست بدون استفاده از Postman باید توکن را با کلید Authorization و به صورت {Bearer {token در Header قرار دهید.
پکیج Sanctum
لاراول در نسخه جدید خود پکیجی به نام Sanctum را منتشر کرد. هدف این پکیج استفاده از راهی مناسب برای احراز هویت در نرم افزارهایی، به نام SPA یا Single Page Application، است. که از طریق فریم ورکهای جاوا اسکریپت توسعه داده میشوند.برای احراز هویت با API در لاراول، کار Sanctum در اینجا به پایان نمیرسد، و این پکیج را در تمامی اپلیکیشنها و سیستمهای Token Base میتوان استفاده کرد. این پکیج همچنین قابلیت ساختن چند Token را برای هر کاربر در اپلیکیشن شما دارد، که حتی میتوانید برای هر توکن چندین قابلیت (Ability) قرار دهید، و از هر توکن به منظور دسترسی به قسمت خاصی از سیستم خود استفاده کنید. به زبان سادهتر به هر توکن میتوانید دسترسیهایی در سیستم خود دهید، که در ادامه بیشتر در مورد آن صحبت خواهیم کرد.نصب پکیج Sanctum
برای نصب پکیج Sanctum از طریق خط فرمان دستور زیر را در پروژه خود اجرا کنید.composer require laravel/sanctum
بعد از نصب پکیج با وارد کردن دستور زیر فایلهای پکیج را به پروژه خود منتقل کنید.
php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"
با اجرای دستور بالا فایلهای پکیج از جمله، فایل sanctum.php در مسیر config، که تنظیمات کلی پکیج پروژهی شما در آن قرار دارد و همچنین فایلهای Migration مربوط به جداول، در پروژه شما قرار داده میشود.
بعد از اجرای دستور بالا نیاز است، در اولین مرحله جداول مربوط به Sanctum را به دیتابیس خود اضافه کنیم. دستور زیر را در خط فرمان پروژه خود اجرا کنید.
php artisan migrate
جدولی که از طریق کد بالا ساخته میشود، در فایل migration مربوط به sanctum در مسیر database/migrations و با نام personal_access_tokens قرار دارد.
در صورتی که میخواهید، فایلهای مربوط به دیتابیس اجرا نشود، در فایل AppServiceProvider.php متد Sanctum::ignoreMigrations را در متد register صدا بزنید.
تنظیمات Sanctum
در فایل config/sanctum.php تنظیمات کلی مربوط به پکیج Sanctum وجود دارد، که در زیر به شما توضیح خواهیم داد.- stateful: اینجا میتوانید دامنههایی که اجازه درخواست به سرور را دارند، تعریف کنید.
- expiration: مربوط به انقضای توکن است، که بر حسب دقیقه محاسبه میشود، و زمانی که null قرار بگیرد، توکن منقضی نخواهد شد.
- middleware: زمانی که از احراز هویت در نرم افزار SPA استفاده میکنید، باید csrf-token هایی که از طریق پکیج Sanctum به نرم افزار داده میشود، اعتبار سنجی شوند. میتوانید Middlewareهای مربوط به این کار را اینجا قرار دهید.
استفاده از پکیج Sanctum در پروژه
میخواهیم در پروژهی خودمان از طریق پکیج Sanctum یک API بنویسیم، که کاربر را از طریق توکن احراز هویت میکند، و بعد از ورود کاربر یک توکن به آن میدهد، و در درخواستهای بعدی با قرار دادن آن توکن در Header درخواست به سرور میگوییم، که درخواست از طریق کدام کاربر به سرور ارسال شده است. در اولین مرحله یک پروژه جدید لاراول با دستور زیر بسازید.composer create-project --prefer-dist laravel/laravel ApiAuthenticateSystem
بعد از انجام مراحل Config پروژه و نصب پکیج Sanctum که در بالا توضیح دادیم، یک مدل User تعریف میکنیم ( که لاراول به طور پیشفرض، مدل User را دارد. )
برای تولید توکن توسط Sanctum باید از Trait به نام HasTokenApi در مدل خود استفاده کنیم، تا متدهای ایجاد و بررسی توکن برای مدل مربوطه، به مدل اضافه شود.
در مدل User کد زیر را قرار دهید.
<?php
namespace App;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;
class User extends Authenticatable
{
use HasApiTokens, Notifiable;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'name', 'email', 'password','username'
];
/**
* 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',
];
}
در قسمت اول تعریف کلاس User از Trait مربوط به پکیج Sanctum با نام HasApiTokens استفاده کردیم، که همچنین در قسمت اول فایل آن را وارد (Import) کردیم.
ورود با Api
یک متد برای ورود و دریافت توکن از طریق Api میخواهیم بسازیم. به این منظور یک Controller ایجاد میکنیم. با استفاده از دستور زیر میتوانید یک Controller ایجاد کنید.php artisan make:controller Auth/UserController
با اجرای دستور بالا یک Controller در مسیر app/Http/Controller/Auth ساخته میشود.
حال باید متد login را به صورت زیر بنویسیم.
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Validation\ValidationException;
use Illuminate\Support\Facades\Hash;
class UserController extends Controller
{
public function login()
{
\request()->validate([
'email' => 'required|email',
'password' => 'required'
]);
$user = User::where('email', \request('email'))->first();
if (! $user || ! Hash::check(\request('password'), $user->password)) {
throw ValidationException::withMessages([
'email' => ['The provided credentials are incorrect.'],
]);
}
return $user->createToken('token_base_name')->plainTextToken;
}
}
در متد لاگین از طریق ایمیل و رمزعبور اول صحت اطلاعات وارد شده را بررسی میکنیم و در صورت صحیح بودن اطلاعات از طریق متد createToken یک توکن برای کاربر مورد نظر در دیتابیس ایجاد میکنیم و توکن خام را به کاربر نشان میدهیم.
حال باید یک مسیر برای ورود در فایل routes/api.php به شکل زیر ایجاد میکنیم.
Route::post('/login', 'Auth\UserController@login');
مسیر بالا را به متد login در فایل UserController.php مرتبط کردیم و زمانی که آدرس localhost:8000/api/login را وارد کنید به متد مربوطه متصل خواهد شد.
زمان درخواست مسیر بالا با متد POST باید در body درخواست دو پارامتر با نام email و password قرار دهیم، که اطلاعات ما خواهند بود. خروجی در نرم افزار Postman به صورت زیر است.

محافظت از مسیر ها
میخواهیم از طریق پکیج Sanctum از مسیرها محافظت کنیم، و یک مسیری بسازیم، که فقط در زمانی که کاربر وارد شده بود، و درخواست دارای توکن بود آن مسیر اجرا شود. برای انجام این کار باید یک guard با درایور token ایجاد کنیم، و ما guard پیشفرض api را تغییر میدهیم. در فایل config/auth.php قسمت guards را به صورت زیر تغییر میدهیم. توجه کنید به صورت پیشفرض نیز لاراول درایور api را token قرار داده است. در غیر این صورت، به صورت زیر تغییر دهید.'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'admin' => [
'driver' => 'session',
'provider' => 'admins'
],
'api' => [
'driver' => 'token',
'provider' => 'users',
'hash' => false,
],
],
تنظیمات بالا مربوط به پروژه آموزش احراز هویت در لاراول است.
حال در فایل routes/api.php یک مسیر به صورت زیر ایجاد میکنیم.
Route::get('/user', function (){
return \request()->user();
})->middleware('auth:sanctum');
مسیر بالا اطلاعات کاربری که به توکن ارسالی در Header، مرتبط است را برمیگرداند.
در Postman به صورت زیر باید در تب Auth نوع احراز هویت را Bearer انتخاب کنید، و در فیلد بعدی توکن را به صورت زیر وارد کنید.

مسیر Logout
زمانی که قرار است از نرم افزار خارج شوید باید عملیات Logout را انجام دهید و در این میان نیاز است توکن ساخته شده را حذف (Revoke) کنید. مسیر Logout را به صورت زیر در فایل routes/api.php قرار دهید.Route::get('/user/logout', function (){
\request()->user()->tokens()->delete();
return response([], 204);
})->middleware('auth:sanctum');
در ارسال درخواست به آدرس بالا نیز باید توکن را بفرستید، زیرا که نیاز است کاربر وارد شده را پیدا کند، و با متد tokens تمامی توکنهای آن را بگیرد، و بعد از آن با delete تمامی توکنهای مربوط به کاربر وارد شده را حذف میکند.
دقت کنید که در کد بالا تمامی توکنهای کاربر حذف میشود، ولی از طریق کد زیر میتوانید توکن مربوطه را پیدا کنید، و فقط آن را حذف کنید.
request()->user()->tokens()->where('id', $id)->delete();
متغیر id همان id مربوط به توکن خواهد بود که میتوانید از راههای مختلف آن را به دست آورید.
دسترسیها در Sanctum
پکیج Sanctum یک ویژگی با نام Ability دارد، که میتوانید در هنگام ایجاد توکن در قسمت ورود برای هر توکن که ایجاد میکنید، یک سری Ability نیز به آن دهید. در این مقاله یک روش نیز برای دسترسی به قسمتهای مختلف پروژه از طریق قابلیتی به نام Policy در لاراول را به شما خواهیم گفت.ایجاد Ability برای کاربر
در فایل UserController.php که در بالاتر ایجاد کردیم، متد login را به صورت زیر تغییر دهید.public function login()
{
$this->validate(\request(),[
'email' => 'required|email',
'password' => 'required'
]);
$user = User::where('email', \request('email'))->first();
if (! $user || ! Hash::check((int)\request('password'), $user->password)) {
throw ValidationException::withMessages([
'email' => ['The provided credentials are incorrect.'],
]);
}
return $user->createToken('token_base_name', ['user:view'])->plainTextToken;
}
در کد بالا در ورودی دوم متد createToken یک آرایه قرار میگیرد، که شامل قابلیتهایی (Ability) است، که توکن میتواند آن را انجام دهد. ما یک آرایه با یک خانه به صورت user:view به آن دادیم، که کاربر در صورت ورود میتواند، در قسمتی از نرم افزار که نیاز به این دسترسی دارد، دسترسی داشته باشد.
ایجاد قوانین دسترسی
میتوانیم از قابلیت Policy در لاراول استفاده کنیم. Policy در لاراول به ما این امکان را میدهد، تا برای دسترسی به مدلهای خود یک قاعده و قانون بنویسیم. برای مثال میخواهیم در یک Controller پنج قسمت لیست، نمایش، اضافه، ویرایش و حذف را برای یک مدل بنویسیم. میتوانیم برای آن مدل یک Policy تعریف کنیم، تا برای هر کدام از عملیات بالا یک قانون بنویسیم. برای ایجاد یک Policy از طریق خط فرمان دستور زیر را اجرا کنید.php artisan make:policy UserPolicy -m User
کلید m- یک مدل را انتخاب میکند.
فایل Policy در مسیر app/Http/Policies قرار میگیرد. فایل UserPolicy را باز کنید.
متدهای مختلفی در آن تعریف شده است، که همچنین شما میتوانید، متد سفارشی خود را نیز بنویسید.
ما در این پروژه میخواهیم، برای نمایش اطلاعات کاربر این روش را بررسی کنیم.
متد view مربوط به نمایش یک کاربر میباشد. دو ورودی میگیرد، که اولی مربوط به کاربر وارد شده است، و دومی مربوط به مدلی است، که قرار است عملیاتی بر روی آن اجرا شود.
متد view را به صورت زیر تغییر دهید.
public function view(User $user, User $model)
{
return $user->tokenCan('user:view') && $user->id === $model->id;
}
دو شرط قرار دادهایم. یکی اینکه کاربر وارد شده دسترسی user:view را داشته باشد، و دوم اینکه مدلی که درخواست میکند دقیقا همان مدل خودش باشد، و نتواند اطلاعات دیگر کاربران را مشاهده کند.
تا اینجا ما قانون مربوط به نمایش اطلاعات کاربر را نوشتهایم. حال در فایل UserController.php که در قسمت اول آموزش ساختهایم، یک متد با نام getUser به صورت زیر مینویسیم.
public function getUser()
{
$this->authorize('view', \request()->user());
return \request()->user();
}
در قسمت اول با استفاده از متد authorize برقرار بودن قانون مربوط به مدل درخواستی که همان مدل کاربر وارد شده است، را بررسی میکنیم. ورودی اول این متد، همان متدهای مربوط در فایل policy است، و ورودی دوم، مدل درخواستی که قصد انجام عملیاتی (در اینجا نمایش) بر روی آن را داریم، است.
در آخرین مرحله باید مسیر مربوط به نمایش اطلاعات کاربر را تغییر دهیم. مسیری که در بالاتر ساختیم را به صورت زیر تغییر دهید.
Route::get('/user','Auth\UserController@getUser')->middleware('auth:sanctum');
حال اگر دوباره یک توکن جدید بگیریم، و به آدرس localhost:8000/api/user به همراه توکن درخواست بزنیم، اطلاعات به ما نمایش داده میشود. ولی اگر توکن ما اجازه دسترسی به آن قسمت را نداشته باشد، (طبق قانون نوشته شده در Policy نباشد) با خطای عدم دسترسی 403 مواجه میشوید.
جمعبندی
در این مقاله نحوهی پیادهسازی احراز هویت با API در لاراول از طریق پکیج Sanctum که توسط خود لاراول توسعه داده شده است، را مورد بررسی قرار دادهایم. این پکیج به صورت Token Base کار میکند. به این معنی که یک توکن به شما میدهد. و در درخواستهای بعدی که نیاز به احراز هویت دارد، آن توکن را باید در Header درخواست خود وارد کنیم. همچنین ویژگی Ability در پکیج را توضیح دادیم. و با یک مثال نشان دادیم، که چطور میتوانید یک سیستم دسترسی در پروژه خود ایجاد کنید.
اگر به یادگیری بیشتر لاراول علاقه داری میتوانی در دوره آموزش پروژه محور لاراول کاربردی (بسته پروژه محور) شرکت کنی، این دوره شامل ۱۲ پروژه کاربردی و پر استفاده در دنیای واقعی است، که تمامی پروژهها به صورت کامل برنامه نویسی خواهند شد، تا دانشجو بتواند با روند ایجاد و تکمیل پروژه به صورت کامل آشنا شود.