نسخه:

پاسپورت لاراول

معرفی

لاراول در حال حاضر انجام احراز هویت از طریق فرم های ورود به سیستم سنتی را آسان می کند، اما در مورد API ها چطور؟ APIها معمولاً از نشانه‌ها برای احراز هویت کاربران استفاده می‌کنند و وضعیت جلسه را بین درخواست‌ها حفظ نمی‌کنند. لاراول احراز هویت API را با استفاده از Laravel Passport آسان می کند، که در عرض چند دقیقه اجرای کامل سرور OAuth2 را برای برنامه لاراول شما فراهم می کند. پاسپورت بر روی سرور League OAuth2 ساخته شده است که توسط اندی میلینگتون و سایمون هامپ نگهداری می شود.

این مستندات فرض می‌کند که شما قبلاً با OAuth2 آشنا هستید. اگر چیزی در مورد OAuth2 نمی دانید، قبل از ادامه با اصطلاحات و ویژگی های کلی OAuth2 آشنا شوید.

ارتقاء پاسپورت

هنگام ارتقاء به نسخه اصلی جدید پاسپورت، مهم است که راهنمای ارتقا را به دقت مرور کنید .

نصب و راه اندازی

برای شروع، Passport را از طریق مدیریت بسته Composer نصب کنید:

composer require laravel/passport

ارائه دهنده خدمات پاسپورت دایرکتوری مهاجرت پایگاه داده خود را با فریم ورک ثبت می کند، بنابراین باید پس از نصب بسته، پایگاه داده خود را مهاجرت کنید. مهاجرت پاسپورت جداول مورد نیاز برنامه شما را برای ذخیره مشتریان و دسترسی به نشانه ها ایجاد می کند:

php artisan migrate

بعد، شما باید passport:install دستور را اجرا کنید. این دستور کلیدهای رمزگذاری مورد نیاز برای تولید توکن های دسترسی ایمن را ایجاد می کند. علاوه بر این، این دستور کلاینت های «دسترسی شخصی» و «اعطای رمز عبور» را ایجاد می کند که برای تولید نشانه های دسترسی استفاده می شود:

php artisan passport:install

پس از اجرای این دستور، Laravel\Passport\HasApiTokens ویژگی را به مدل خود اضافه کنید App\User . این ویژگی چند روش کمکی به مدل شما ارائه می دهد که به شما امکان می دهد توکن و محدوده کاربر تأیید شده را بررسی کنید:

<?php
 
namespace App;
 
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Passport\HasApiTokens;
 
class User extends Authenticatable
{
use HasApiTokens, Notifiable;
}

در مرحله بعد، باید Passport::routes متد را در boot متد خود فراخوانی کنید AuthServiceProvider . این روش مسیرهای لازم برای صدور توکن های دسترسی و لغو توکن های دسترسی، کلاینت ها و نشانه های دسترسی شخصی را ثبت می کند:

<?php
 
namespace App\Providers;
 
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Gate;
use Laravel\Passport\Passport;
 
class AuthServiceProvider extends ServiceProvider
{
/**
* The policy mappings for the application.
*
* @var array
*/
protected $policies = [
'App\Model' => 'App\Policies\ModelPolicy',
];
 
/**
* Register any authentication / authorization services.
*
* @return void
*/
public function boot()
{
$this->registerPolicies();
 
Passport::routes();
}
}

در نهایت، در فایل پیکربندی خود config/auth.php ، باید driver گزینه ی api authentication guard را روی passport . این به برنامه شما دستور می دهد تا TokenGuard هنگام احراز هویت درخواست های API ورودی از Passport استفاده کند :

'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
 
'api' => [
'driver' => 'passport',
'provider' => 'users',
],
],

سفارشی سازی مهاجرت

اگر نمی‌خواهید از مهاجرت‌های پیش‌فرض Passport استفاده کنید، باید متد موجود Passport::ignoreMigrations در register متد خود را فراخوانی کنید AppServiceProvider . می توانید مهاجرت های پیش فرض را با استفاده از صادر کنید php artisan vendor:publish --tag=passport-migrations .

به طور پیش فرض، Passport از یک ستون عدد صحیح برای ذخیره سازی استفاده می کند user_id . اگر برنامه شما از نوع ستون متفاوتی برای شناسایی کاربران استفاده می‌کند (به عنوان مثال: UUID)، باید پس از انتشار آنها، مهاجرت‌های پیش‌فرض Passport را تغییر دهید.

Frontend Quick Start

برای استفاده از اجزای Passport Vue، باید از چارچوب جاوا اسکریپت Vue استفاده کنید . این کامپوننت ها از فریم ورک Bootstrap CSS نیز استفاده می کنند. با این حال، حتی اگر از این ابزارها استفاده نمی کنید، مؤلفه ها به عنوان یک مرجع ارزشمند برای پیاده سازی frontend خودتان عمل می کنند.

پاسپورت دارای یک JSON API است که می‌توانید از آن برای ایجاد مشتری و نشانه‌های دسترسی شخصی به کاربران خود استفاده کنید. با این حال، کدنویسی یک فرانت اند برای تعامل با این API ها می تواند زمان بر باشد. بنابراین، Passport همچنین شامل اجزای Vue از پیش ساخته شده است که می‌توانید به عنوان نمونه پیاده‌سازی یا نقطه شروع برای پیاده‌سازی خود استفاده کنید.

برای انتشار اجزای Passport Vue، از vendor:publish دستور Artisan استفاده کنید:

php artisan vendor:publish --tag=passport-components

اجزای منتشر شده در resources/js/components دایرکتوری شما قرار خواهند گرفت. پس از انتشار کامپوننت ها، باید آنها را در resources/js/app.js فایل خود ثبت کنید:

Vue.component(
'passport-clients',
require('./components/passport/Clients.vue').default
);
 
Vue.component(
'passport-authorized-clients',
require('./components/passport/AuthorizedClients.vue').default
);
 
Vue.component(
'passport-personal-access-tokens',
require('./components/passport/PersonalAccessTokens.vue').default
);

قبل از Laravel نسخه 5.7.19، الحاق .default در هنگام ثبت اجزا منجر به خطای کنسول می شود. توضیحی برای این تغییر را می توان در یادداشت های انتشار Laravel Mix v4.0.0 یافت .

پس از ثبت کامپوننت ها، مطمئن شوید که npm run dev برای کامپایل مجدد دارایی های خود اجرا کنید. هنگامی که دارایی های خود را مجدداً کامپایل کردید، می توانید مؤلفه ها را در یکی از قالب های برنامه خود قرار دهید تا شروع به ایجاد کلاینت ها و نشانه های دسترسی شخصی کنید:

<passport-clients></passport-clients>
<passport-authorized-clients></passport-authorized-clients>
<passport-personal-access-tokens></passport-personal-access-tokens>

استقرار پاسپورت

هنگام استقرار Passport برای اولین بار در سرورهای تولیدی خود، احتمالاً باید این passport:keys دستور را اجرا کنید. این دستور کلیدهای رمزگذاری مورد نیاز Passport را برای تولید رمز دسترسی ایجاد می کند. کلیدهای تولید شده معمولاً در کنترل منبع نگهداری نمی شوند:

php artisan passport:keys

در صورت لزوم، می‌توانید مسیری را که کلیدهای پاسپورت باید از آنجا بارگیری شوند، تعیین کنید. Passport::loadKeysFrom برای انجام این کار می توانید از روش زیر استفاده کنید :

/**
* Register any authentication / authorization services.
*
* @return void
*/
public function boot()
{
$this->registerPolicies();
 
Passport::routes();
 
Passport::loadKeysFrom('/secret-keys/oauth');
}

علاوه بر این، می‌توانید فایل پیکربندی Passport را با استفاده از، منتشر کنید php artisan vendor:publish --tag=passport-config ، که سپس گزینه بارگیری کلیدهای رمزگذاری را از متغیرهای محیطی شما ارائه می‌کند:

PASSPORT_PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----
<private key here>
-----END RSA PRIVATE KEY-----"
 
PASSPORT_PUBLIC_KEY="-----BEGIN PUBLIC KEY-----
<public key here>
-----END PUBLIC KEY-----"

پیکربندی

طول عمر رمز

به طور پیش فرض، پاسپورت توکن های دسترسی طولانی مدت را صادر می کند که پس از یک سال منقضی می شوند. اگر می‌خواهید طول عمر توکن طولانی‌تر/کوتاه‌تر را پیکربندی کنید، می‌توانید از روش‌های tokensExpireIn ، refreshTokensExpireIn و و استفاده کنید personalAccessTokensExpireIn . این متدها باید از boot متد شما فراخوانی شوند AuthServiceProvider :

/**
* Register any authentication / authorization services.
*
* @return void
*/
public function boot()
{
$this->registerPolicies();
 
Passport::routes();
 
Passport::tokensExpireIn(now()->addDays(15));
 
Passport::refreshTokensExpireIn(now()->addDays(30));
 
Passport::personalAccessTokensExpireIn(now()->addMonths(6));
}

نادیده گرفتن مدل های پیش فرض

شما می توانید مدل های استفاده شده داخلی توسط پاسپورت را گسترش دهید:

use Laravel\Passport\Client as PassportClient;
 
class Client extends PassportClient
{
// ...
}

سپس، می توانید به Passport دستور دهید که از مدل های سفارشی شما از طریق Passport کلاس استفاده کند:

use App\Models\Passport\AuthCode;
use App\Models\Passport\Client;
use App\Models\Passport\PersonalAccessClient;
use App\Models\Passport\Token;
 
/**
* Register any authentication / authorization services.
*
* @return void
*/
public function boot()
{
$this->registerPolicies();
 
Passport::routes();
 
Passport::useTokenModel(Token::class);
Passport::useClientModel(Client::class);
Passport::useAuthCodeModel(AuthCode::class);
Passport::usePersonalAccessClientModel(PersonalAccessClient::class);
}

صدور توکن های دسترسی

استفاده از OAuth2 با کدهای مجوز، روشی است که اکثر توسعه دهندگان با OAuth2 آشنا هستند. هنگام استفاده از کدهای مجوز، یک برنامه مشتری کاربر را به سرور شما هدایت می کند، جایی که آنها درخواست صدور رمز دسترسی به مشتری را تأیید یا رد می کنند.

مدیریت مشتریان

ابتدا، توسعه‌دهندگانی که برنامه‌هایی را می‌سازند که نیاز به تعامل با API برنامه شما دارند، باید برنامه خود را با ایجاد یک «کلینت» در اپلیکیشن شما ثبت کنند. به طور معمول، این شامل ارائه نام برنامه و یک URL است که برنامه شما می تواند پس از تأیید درخواست مجوز توسط کاربران، به آن هدایت شود.

دستور passport:client _

ساده ترین راه برای ایجاد مشتری استفاده از passport:client دستور Artisan است. این دستور ممکن است برای ایجاد کلاینت های خود برای آزمایش عملکرد OAuth2 استفاده شود. هنگامی که دستور را اجرا می کنید client ، Passport از شما می خواهد اطلاعات بیشتری در مورد مشتری خود دریافت کنید و یک شناسه مشتری و راز را در اختیار شما قرار می دهد:

php artisan passport:client

تغییر مسیر URL ها

اگر می‌خواهید چندین URL تغییر مسیر را برای مشتری خود در لیست سفید قرار دهید، می‌توانید آنها را با استفاده از یک لیست محدود شده با کاما مشخص کنید وقتی که با دستور از شما خواسته شد URL را انتخاب کنید passport:client :

http://example.com/callback,http://examplefoo.com/callback

هر URL که حاوی کاما است باید کدگذاری شود.

JSON API

از آنجایی که کاربران شما نمی توانند از این client دستور استفاده کنند، Passport یک API JSON ارائه می دهد که می توانید از آن برای ایجاد کلاینت استفاده کنید. این کار شما را از مشکل کدنویسی دستی کنترلرها برای ایجاد، به‌روزرسانی و حذف کلاینت‌ها نجات می‌دهد.

با این حال، باید API JSON Passport را با ظاهر خود جفت کنید تا داشبوردی برای کاربران خود فراهم کنید تا مشتریان خود را مدیریت کنند. در زیر، همه نقاط پایانی API را برای مدیریت مشتریان بررسی می‌کنیم. برای راحتی، از Axios برای نشان دادن درخواست های HTTP به نقاط پایانی استفاده می کنیم .

JSON API توسط میان افزار web و auth میان افزار محافظت می شود. بنابراین، ممکن است فقط از برنامه خود شما فراخوانی شود. امکان فراخوانی از منبع خارجی وجود ندارد.

اگر نمی‌خواهید کل فرانت‌اند مدیریت مشتری را خودتان پیاده‌سازی کنید، می‌توانید از راه‌اندازی سریع frontend استفاده کنید تا در عرض چند دقیقه یک ظاهر کاملاً کاربردی داشته باشید.

GET /oauth/clients

این مسیر همه کلاینت ها را برای کاربر احراز هویت شده برمی گرداند. این در درجه اول برای فهرست کردن همه مشتریان کاربر مفید است تا آنها بتوانند آنها را ویرایش یا حذف کنند:

axios.get('/oauth/clients')
.then(response => {
console.log(response.data);
});

POST /oauth/clients

این مسیر برای ایجاد مشتریان جدید استفاده می شود. به دو داده نیاز دارد: مشتری name و redirect URL. URL redirect جایی است که کاربر پس از تأیید یا رد درخواست مجوز هدایت می شود.

هنگامی که یک کلاینت ایجاد می شود، شناسه مشتری و راز مشتری برای آن صادر می شود. این مقادیر هنگام درخواست نشانه های دسترسی از برنامه شما استفاده می شود. مسیر ایجاد مشتری، نمونه مشتری جدید را برمی گرداند:

const data = {
name: 'Client Name',
redirect: 'http://example.com/callback'
};
 
axios.post('/oauth/clients', data)
.then(response => {
console.log(response.data);
})
.catch (response => {
// List errors on response...
});

PUT /oauth/clients/{client-id}

این مسیر برای به روز رسانی کلاینت ها استفاده می شود. به دو داده نیاز دارد: مشتری name و redirect URL. URL redirect جایی است که کاربر پس از تأیید یا رد درخواست مجوز هدایت می شود. مسیر نمونه مشتری به روز شده را برمی گرداند:

const data = {
name: 'New Client Name',
redirect: 'http://example.com/callback'
};
 
axios.put('/oauth/clients/' + clientId, data)
.then(response => {
console.log(response.data);
})
.catch (response => {
// List errors on response...
});

DELETE /oauth/clients/{client-id}

این مسیر برای حذف کلاینت ها استفاده می شود:

axios.delete('/oauth/clients/' + clientId)
.then(response => {
//
});

درخواست توکن

تغییر مسیر برای مجوز

هنگامی که یک کلاینت ایجاد شد، توسعه دهندگان ممکن است از شناسه مشتری و راز خود برای درخواست کد مجوز و رمز دسترسی از برنامه شما استفاده کنند. ابتدا، برنامه مصرف کننده باید یک درخواست تغییر مسیر به مسیر برنامه شما /oauth/authorize مانند زیر ارسال کند:

Route::get('/redirect', function (Request $request) {
$request->session()->put('state', $state = Str::random(40));
 
$query = http_build_query([
'client_id' => 'client-id',
'redirect_uri' => 'http://example.com/callback',
'response_type' => 'code',
'scope' => '',
'state' => $state,
]);
 
return redirect('http://your-app.com/oauth/authorize?'.$query);
});

به یاد داشته باشید، /oauth/authorize مسیر قبلاً با Passport::routes روش تعریف شده است. نیازی به تعریف دستی این مسیر ندارید.

تایید درخواست

هنگام دریافت درخواست های مجوز، پاسپورت به طور خودکار یک الگو را به کاربر نمایش می دهد که به کاربر اجازه می دهد درخواست مجوز را تأیید یا رد کند. اگر آنها درخواست را تأیید کنند، به همان چیزی که redirect_uri توسط برنامه مصرف کننده مشخص شده است هدایت می شوند. باید با URL که هنگام ایجاد مشتری مشخص شده بود redirect_uri مطابقت داشته باشد . redirect

اگر می‌خواهید صفحه تأیید مجوز را سفارشی کنید، می‌توانید نماهای پاسپورت را با استفاده از vendor:publish دستور Artisan منتشر کنید. نماهای منتشر شده در resources/views/vendor/passport :

php artisan vendor:publish --tag=passport-views

گاهی اوقات ممکن است بخواهید از درخواست مجوز صرفنظر کنید، مانند زمانی که یک مشتری شخص اول را مجوز می دهید. شما می توانید این کار را با گسترش Client مدل و تعریف یک skipsAuthorization روش انجام دهید. در صورت skipsAuthorization بازگرداندن true مشتری تأیید می شود و کاربر redirect_uri بلافاصله به آدرس زیر هدایت می شود:

<?php
 
namespace App\Models\Passport;
 
use Laravel\Passport\Client as BaseClient;
 
class Client extends BaseClient
{
/**
* Determine if the client should skip the authorization prompt.
*
* @return bool
*/
public function skipsAuthorization()
{
return $this->firstParty();
}
}

تبدیل کدهای مجوز به توکن ها

اگر کاربر درخواست مجوز را تأیید کند، به برنامه مصرف کننده هدایت می شود. مصرف کننده ابتدا باید state پارامتر را در برابر مقداری که قبل از تغییر مسیر ذخیره شده بود تأیید کند. اگر پارامتر حالت مطابقت داشته باشد، مصرف کننده باید POST درخواستی برای درخواست توکن دسترسی به برنامه شما ارسال کند. درخواست باید شامل کد مجوزی باشد که زمانی که کاربر درخواست مجوز را تأیید کرد توسط برنامه شما صادر شده است. در این مثال، از کتابخانه HTTP Guzzle برای ارسال درخواست استفاده می کنیم POST :

Route::get('/callback', function (Request $request) {
$state = $request->session()->pull('state');
 
throw_unless(
strlen($state) > 0 && $state === $request->state,
InvalidArgumentException::class
);
 
$http = new GuzzleHttp\Client;
 
$response = $http->post('http://your-app.com/oauth/token', [
'form_params' => [
'grant_type' => 'authorization_code',
'client_id' => 'client-id',
'client_secret' => 'client-secret',
'redirect_uri' => 'http://example.com/callback',
'code' => $request->code,
],
]);
 
return json_decode((string) $response->getBody(), true);
});

این مسیر یک پاسخ JSON حاوی , و ویژگی ها /oauth/token را برمی گرداند . این ویژگی حاوی تعداد ثانیه هایی است که تا زمانی که نشانه دسترسی منقضی شود. access_token refresh_token expires_in expires_in

مانند /oauth/authorize مسیر، /oauth/token مسیر نیز با روش برای شما تعریف می شود Passport::routes . نیازی به تعریف دستی این مسیر نیست. به طور پیش فرض، این مسیر با استفاده از تنظیمات میان افزار کاهش می یابد ThrottleRequests .

نشانه های تازه کردن

اگر برنامه شما توکن‌های دسترسی کوتاه‌مدت صادر می‌کند، کاربران باید توکن‌های دسترسی خود را از طریق توکن تازه‌سازی که هنگام صدور توکن دسترسی در اختیار آن‌ها قرار داده بود، تازه‌سازی کنند. در این مثال، از کتابخانه HTTP Guzzle برای به‌روزرسانی توکن استفاده می‌کنیم:

$http = new GuzzleHttp\Client;
 
$response = $http->post('http://your-app.com/oauth/token', [
'form_params' => [
'grant_type' => 'refresh_token',
'refresh_token' => 'the-refresh-token',
'client_id' => 'client-id',
'client_secret' => 'client-secret',
'scope' => '',
],
]);
 
return json_decode((string) $response->getBody(), true);

این مسیر یک پاسخ JSON حاوی , و ویژگی ها /oauth/token را برمی گرداند . این ویژگی حاوی تعداد ثانیه هایی است که تا زمانی که نشانه دسترسی منقضی شود. access_token refresh_token expires_in expires_in

پاکسازی توکن ها

هنگامی که توکن ها باطل یا منقضی شدند، ممکن است بخواهید آنها را از پایگاه داده پاک کنید. پاسپورت با دستوری ارسال می شود که می تواند این کار را برای شما انجام دهد:

# Purge revoked and expired tokens and auth codes...
php artisan passport:purge
 
# Only purge revoked tokens and auth codes...
php artisan passport:purge --revoked
 
# Only purge expired tokens and auth codes...
php artisan passport:purge --expired

همچنین می‌توانید یک کار زمان‌بندی‌شده را در کلاس کنسول خود پیکربندی کنید Kernel تا به‌طور خودکار توکن‌هایتان را بر اساس یک زمان‌بندی هرس کند:

/**
* Define the application's command schedule.
*
* @param \Illuminate\Console\Scheduling\Schedule $schedule
* @return void
*/
protected function schedule(Schedule $schedule)
{
$schedule->command('passport:purge')->hourly();
}

اعطای کد مجوز با PKCE

اعطای کد مجوز با "کلید اثبات برای تبادل کد" (PKCE) راهی امن برای احراز هویت برنامه های کاربردی تک صفحه ای یا برنامه های کاربردی بومی برای دسترسی به API شما است. این کمک هزینه زمانی باید استفاده شود که نمی‌توانید تضمین کنید که راز مشتری به‌طور محرمانه ذخیره می‌شود یا به منظور کاهش خطر رهگیری کد مجوز توسط مهاجم. ترکیبی از "تأیید کننده کد" و "چالش کد" جایگزین رمز مشتری در هنگام مبادله کد مجوز برای یک نشانه دسترسی می شود.

ایجاد مشتری

قبل از اینکه برنامه شما بتواند از طریق اعطای کد مجوز با PKCE توکن صادر کند، باید یک کلاینت با قابلیت PKCE ایجاد کنید. می توانید این کار را با استفاده از passport:client دستور با --public گزینه زیر انجام دهید:

php artisan passport:client --public

درخواست توکن

تأیید کننده کد و چالش کد

از آنجایی که این مجوز یک راز مشتری ارائه نمی‌کند، توسعه‌دهندگان باید ترکیبی از تأییدکننده کد و چالش کد را ایجاد کنند تا یک رمز را درخواست کنند.

تأیید کننده کد باید یک رشته تصادفی بین 43 تا 128 کاراکتر باشد که شامل حروف، اعداد و ،،،، همانطور "-" که در مشخصات RFC 7636 تعریف شده است باشد . "." "_" "~"

چالش کد باید یک رشته رمزگذاری شده Base64 با URL و کاراکترهای ایمن برای نام فایل باشد. کاراکترهای انتهایی '=' باید حذف شوند و هیچ خط شکنی، فضای خالی یا سایر کاراکترهای اضافی نباید وجود داشته باشد.

$encoded = base64_encode(hash('sha256', $code_verifier, true));
 
$codeChallenge = strtr(rtrim($encoded, '='), '+/', '-_');

تغییر مسیر برای مجوز

پس از ایجاد مشتری، می‌توانید از شناسه مشتری و تأییدکننده کد تولید شده و چالش کد برای درخواست کد مجوز و رمز دسترسی از برنامه خود استفاده کنید. ابتدا، برنامه مصرف کننده باید یک درخواست تغییر مسیر به /oauth/authorize مسیر برنامه شما ارسال کند:

Route::get('/redirect', function (Request $request) {
$request->session()->put('state', $state = Str::random(40));
 
$request->session()->put('code_verifier', $code_verifier = Str::random(128));
 
$codeChallenge = strtr(rtrim(
base64_encode(hash('sha256', $code_verifier, true))
, '='), '+/', '-_');
 
$query = http_build_query([
'client_id' => 'client-id',
'redirect_uri' => 'http://example.com/callback',
'response_type' => 'code',
'scope' => '',
'state' => $state,
'code_challenge' => $codeChallenge,
'code_challenge_method' => 'S256',
]);
 
return redirect('http://your-app.com/oauth/authorize?'.$query);
});

تبدیل کدهای مجوز به توکن ها

اگر کاربر درخواست مجوز را تأیید کند، به برنامه مصرف کننده هدایت می شود. مصرف کننده باید state پارامتر را در برابر مقداری که قبل از تغییر مسیر ذخیره شده است، تأیید کند، همانطور که در اعطای کد مجوز استاندارد وجود دارد.

اگر پارامتر حالت مطابقت داشته باشد، مصرف کننده باید POST درخواستی برای درخواست توکن دسترسی به برنامه شما صادر کند. این درخواست باید شامل کد مجوزی باشد که زمانی که کاربر درخواست مجوز را تأیید کرد توسط برنامه شما صادر شده است به همراه تأییدکننده کد اولیه ایجاد شده:

Route::get('/callback', function (Request $request) {
$state = $request->session()->pull('state');
 
$codeVerifier = $request->session()->pull('code_verifier');
 
throw_unless(
strlen($state) > 0 && $state === $request->state,
InvalidArgumentException::class
);
 
$response = (new GuzzleHttp\Client)->post('http://your-app.com/oauth/token', [
'form_params' => [
'grant_type' => 'authorization_code',
'client_id' => 'client-id',
'redirect_uri' => 'http://example.com/callback',
'code_verifier' => $codeVerifier,
'code' => $request->code,
],
]);
 
return json_decode((string) $response->getBody(), true);
});

رمزهای اعطای رمز عبور

اعطای رمز عبور OAuth2 به دیگر مشتریان شخص اول شما، مانند یک برنامه تلفن همراه، اجازه می دهد تا با استفاده از آدرس ایمیل / نام کاربری و رمز عبور، رمز دسترسی به دست آورند. این به شما امکان می‌دهد تا توکن‌های دسترسی را به طور ایمن برای مشتریان شخص اول خود صادر کنید، بدون اینکه کاربران خود را ملزم به گذراندن کل جریان تغییر مسیر کد مجوز OAuth2 کنید.

ایجاد مشتری اعطای رمز عبور

قبل از اینکه برنامه شما بتواند از طریق اعطای رمز عبور توکن صادر کند، باید یک کلاینت اعطای رمز عبور ایجاد کنید. می توانید این کار را با استفاده از passport:client دستور با --password گزینه انجام دهید. اگر قبلاً دستور را اجرا کرده اید passport:install ، نیازی به اجرای این دستور ندارید:

php artisan passport:client --password

درخواست توکن

هنگامی که یک کلاینت اعطای رمز عبور ایجاد کردید، می توانید با ارسال یک POST درخواست به /oauth/token مسیر با آدرس ایمیل و رمز عبور کاربر، یک نشانه دسترسی درخواست کنید. به یاد داشته باشید، این مسیر قبلاً توسط Passport::routes روش ثبت شده است، بنابراین نیازی به تعریف دستی آن نیست. اگر درخواست موفقیت آمیز باشد، پاسخ JSON را از سرور دریافت خواهید access_token کرد refresh_token :

$http = new GuzzleHttp\Client;
 
$response = $http->post('http://your-app.com/oauth/token', [
'form_params' => [
'grant_type' => 'password',
'client_id' => 'client-id',
'client_secret' => 'client-secret',
'username' => 'taylor@laravel.com',
'password' => 'my-password',
'scope' => '',
],
]);
 
return json_decode((string) $response->getBody(), true);

به یاد داشته باشید که توکن های دسترسی به طور پیش فرض عمر طولانی دارند. با این حال، در صورت نیاز می توانید حداکثر طول عمر رمز دسترسی خود را پیکربندی کنید .

درخواست همه دامنه ها

هنگام استفاده از اعطای رمز عبور یا اعطای اعتبار مشتری، ممکن است بخواهید توکن را برای همه حوزه‌های پشتیبانی شده توسط برنامه خود تأیید کنید. شما می توانید این کار را با درخواست * دامنه انجام دهید. اگر دامنه را درخواست کنید * ، can متد موجود در نمونه توکن همیشه برمی‌گردد true . این محدوده ممکن است فقط به یک توکن اختصاص داده شود که با استفاده از password یا client_credentials کمک مالی صادر می شود:

$response = $http->post('http://your-app.com/oauth/token', [
'form_params' => [
'grant_type' => 'password',
'client_id' => 'client-id',
'client_secret' => 'client-secret',
'username' => 'taylor@laravel.com',
'password' => 'my-password',
'scope' => '*',
],
]);

سفارشی کردن فیلد نام کاربری

هنگام احراز هویت با استفاده از اعطای رمز عبور، Passport از email ویژگی مدل شما به عنوان "نام کاربری" استفاده می کند. با این حال، می توانید این رفتار را با تعریف findForPassport روشی در مدل خود سفارشی کنید:

<?php
 
namespace App;
 
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Passport\HasApiTokens;
 
class User extends Authenticatable
{
use HasApiTokens, Notifiable;
 
/**
* Find the user instance for the given username.
*
* @param string $username
* @return \App\User
*/
public function findForPassport($username)
{
return $this->where('username', $username)->first();
}
}

سفارشی کردن اعتبارسنجی رمز عبور

هنگام احراز هویت با استفاده از اعطای رمز عبور، Passport password از ویژگی مدل شما برای تأیید اعتبار رمز عبور داده شده استفاده می کند. اگر مدل شما ویژگی ندارد password یا می‌خواهید منطق اعتبارسنجی رمز عبور را سفارشی کنید، می‌توانید validateForPassportPasswordGrant روشی را بر روی مدل خود تعریف کنید:

<?php
 
namespace App;
 
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Support\Facades\Hash;
use Laravel\Passport\HasApiTokens;
 
class User extends Authenticatable
{
use HasApiTokens, Notifiable;
 
/**
* Validate the password of the user for the Passport password grant.
*
* @param string $password
* @return bool
*/
public function validateForPassportPasswordGrant($password)
{
return Hash::check($password, $this->password);
}
}

توکن های اعطای ضمنی

کمک هزینه ضمنی مشابه اعطای کد مجوز است. با این حال، توکن بدون تبادل کد مجوز به مشتری بازگردانده می شود. این کمک هزینه بیشتر برای جاوا اسکریپت یا برنامه های تلفن همراه استفاده می شود که در آنها اعتبار مشتری نمی تواند به طور ایمن ذخیره شود. برای فعال کردن کمک هزینه، enableImplicitGrant روش موجود در خود را فراخوانی کنید AuthServiceProvider :

/**
* Register any authentication / authorization services.
*
* @return void
*/
public function boot()
{
$this->registerPolicies();
 
Passport::routes();
 
Passport::enableImplicitGrant();
}

هنگامی که کمک مالی فعال شد، توسعه دهندگان ممکن است از شناسه مشتری خود برای درخواست رمز دسترسی از برنامه شما استفاده کنند. برنامه مصرف کننده باید یک درخواست تغییر مسیر به مسیر برنامه شما /oauth/authorize مانند زیر ارسال کند:

Route::get('/redirect', function (Request $request) {
$request->session()->put('state', $state = Str::random(40));
 
$query = http_build_query([
'client_id' => 'client-id',
'redirect_uri' => 'http://example.com/callback',
'response_type' => 'token',
'scope' => '',
'state' => $state,
]);
 
return redirect('http://your-app.com/oauth/authorize?'.$query);
});

به یاد داشته باشید، /oauth/authorize مسیر قبلاً با Passport::routes روش تعریف شده است. نیازی به تعریف دستی این مسیر ندارید.

توکن های اعطای اعتبار مشتری

اعطای اعتبار مشتری برای احراز هویت ماشین به ماشین مناسب است. برای مثال، ممکن است از این کمک هزینه در یک کار برنامه ریزی شده استفاده کنید که وظایف تعمیر و نگهداری را از طریق یک API انجام می دهد.

قبل از اینکه برنامه شما بتواند از طریق اعطای اعتبار مشتری، توکن صادر کند، باید یک مشتری اعطای اعتبار مشتری ایجاد کنید. می توانید این کار را با استفاده از --client گزینه passport:client دستور انجام دهید:

php artisan passport:client --client

در مرحله بعد، برای استفاده از این نوع کمک هزینه، باید CheckClientCredentials میان افزار را به $routeMiddleware ویژگی فایل خود اضافه کنید app/Http/Kernel.php :

use Laravel\Passport\Http\Middleware\CheckClientCredentials;
 
protected $routeMiddleware = [
'client' => CheckClientCredentials::class,
];

سپس میان افزار را به یک مسیر وصل کنید:

Route::get('/orders', function (Request $request) {
...
})->middleware('client');

client برای محدود کردن دسترسی به مسیر به محدوده‌های خاص، می‌توانید هنگام اتصال میان‌افزار به مسیر ، فهرستی از محدوده‌های مورد نیاز با کاما ارائه دهید :

Route::get('/orders', function (Request $request) {
...
})->middleware('client:check-status,your-scope');

بازیابی توکن ها

برای بازیابی یک نشانه با استفاده از این نوع کمک هزینه، یک درخواست به oauth/token نقطه پایانی ارسال کنید:

$guzzle = new GuzzleHttp\Client;
 
$response = $guzzle->post('http://your-app.com/oauth/token', [
'form_params' => [
'grant_type' => 'client_credentials',
'client_id' => 'client-id',
'client_secret' => 'client-secret',
'scope' => 'your-scope',
],
]);
 
return json_decode((string) $response->getBody(), true)['access_token'];

توکن های دسترسی شخصی

گاهی اوقات، کاربران شما ممکن است بخواهند بدون عبور از جریان تغییر مسیر کد مجوز معمولی، توکن های دسترسی را برای خود صادر کنند. اجازه دادن به کاربران برای صدور نشانه برای خود از طریق UI برنامه شما می تواند برای اجازه دادن به کاربران برای آزمایش با API شما مفید باشد یا ممکن است به عنوان یک رویکرد ساده تر برای صدور توکن های دسترسی به طور کلی باشد.

ایجاد مشتری دسترسی شخصی

قبل از اینکه برنامه شما بتواند توکن های دسترسی شخصی صادر کند، باید یک کلاینت دسترسی شخصی ایجاد کنید. می توانید این کار را با استفاده از passport:client دستور با --personal گزینه انجام دهید. اگر قبلاً دستور را اجرا کرده اید passport:install ، نیازی به اجرای این دستور ندارید:

php artisan passport:client --personal

اگر قبلاً یک کلاینت دسترسی شخصی تعریف کرده‌اید، می‌توانید به Passport دستور دهید تا با استفاده از این personalAccessClientId روش از آن استفاده کند. به طور معمول، این متد باید از boot متد شما فراخوانی شود AuthServiceProvider :

/**
* Register any authentication / authorization services.
*
* @return void
*/
public function boot()
{
$this->registerPolicies();
 
Passport::routes();
 
Passport::personalAccessClientId('client-id');
}

مدیریت توکن های دسترسی شخصی

هنگامی که یک کلاینت دسترسی شخصی ایجاد کردید، می توانید با استفاده از createToken روش موجود در User نمونه مدل، توکن هایی را برای یک کاربر مشخص صادر کنید. این createToken متد نام نشانه را به عنوان اولین آرگومان خود و یک آرایه اختیاری از دامنه ها را به عنوان آرگومان دوم می پذیرد:

$user = App\User::find(1);
 
// Creating a token without scopes...
$token = $user->createToken('Token Name')->accessToken;
 
// Creating a token with scopes...
$token = $user->createToken('My Token', ['place-orders'])->accessToken;

JSON API

پاسپورت همچنین دارای یک API JSON برای مدیریت توکن های دسترسی شخصی است. می‌توانید این را با ظاهر خود جفت کنید تا به کاربران خود داشبوردی برای مدیریت نشانه‌های دسترسی شخصی ارائه دهید. در زیر، تمام نقاط پایانی API را برای مدیریت نشانه‌های دسترسی شخصی بررسی می‌کنیم. برای راحتی، از Axios برای نشان دادن درخواست های HTTP به نقاط پایانی استفاده می کنیم .

JSON API توسط میان افزار web و auth میان افزار محافظت می شود. بنابراین، ممکن است فقط از برنامه خود شما فراخوانی شود. امکان فراخوانی از منبع خارجی وجود ندارد.

اگر نمی‌خواهید خودتان frontend توکن دسترسی شخصی را پیاده‌سازی کنید، می‌توانید از frontend Quick Start استفاده کنید تا در عرض چند دقیقه یک ظاهر کاملاً کاربردی داشته باشید.

GET /oauth/scopes

این مسیر تمام محدوده های تعریف شده برای برنامه شما را برمی گرداند. می‌توانید از این مسیر برای فهرست کردن دامنه‌هایی که کاربر ممکن است به یک نشانه دسترسی شخصی اختصاص دهد استفاده کنید:

axios.get('/oauth/scopes')
.then(response => {
console.log(response.data);
});

GET /oauth/personal-access-tokens

این مسیر تمام نشانه های دسترسی شخصی را که کاربر احراز هویت شده ایجاد کرده است، برمی گرداند. این در درجه اول برای فهرست کردن تمام نشانه های کاربر مفید است تا آنها بتوانند آنها را ویرایش یا حذف کنند:

axios.get('/oauth/personal-access-tokens')
.then(response => {
console.log(response.data);
});

POST /oauth/personal-access-tokens

این مسیر توکن های دسترسی شخصی جدیدی ایجاد می کند. به دو قطعه داده نیاز دارد: نشانه name و داده ای scopes که باید به توکن اختصاص داده شود:

const data = {
name: 'Token Name',
scopes: []
};
 
axios.post('/oauth/personal-access-tokens', data)
.then(response => {
console.log(response.data.accessToken);
})
.catch (response => {
// List errors on response...
});

DELETE /oauth/personal-access-tokens/{token-id}

این مسیر ممکن است برای حذف نشانه های دسترسی شخصی استفاده شود:

axios.delete('/oauth/personal-access-tokens/' + tokenId);

حفاظت از مسیرها

از طریق Middleware

پاسپورت شامل یک محافظ احراز هویت است که توکن های دسترسی را در درخواست های دریافتی تأیید می کند. هنگامی که api محافظ را برای استفاده از درایور پیکربندی کردید passport ، فقط باید auth:api میان افزار را در مسیرهایی که به یک نشانه دسترسی معتبر نیاز دارند، مشخص کنید:

Route::get('/user', function () {
//
})->middleware('auth:api');

عبور از رمز دسترسی

هنگام فراخوانی مسیرهایی که توسط پاسپورت محافظت می شوند، مصرف کنندگان API برنامه شما باید توکن دسترسی خود را به عنوان یک Bearer توکن در Authorization هدر درخواست خود مشخص کنند. به عنوان مثال، هنگام استفاده از کتابخانه HTTP Guzzle:

$response = $client->request('GET', '/api/user', [
'headers' => [
'Accept' => 'application/json',
'Authorization' => 'Bearer '.$accessToken,
],
]);

محدوده توکن

Scopes به مشتریان API شما اجازه می دهد هنگام درخواست مجوز برای دسترسی به یک حساب، مجموعه خاصی از مجوزها را درخواست کنند. به عنوان مثال، اگر در حال ساخت یک برنامه تجارت الکترونیک هستید، همه مصرف کنندگان API به توانایی سفارش دادن نیاز نخواهند داشت. درعوض، می‌توانید به مصرف‌کنندگان اجازه دهید فقط برای دسترسی به وضعیت ارسال سفارش مجوز درخواست کنند. به عبارت دیگر، دامنه ها به کاربران برنامه شما اجازه می دهند تا اقداماتی را که یک برنامه شخص ثالث می تواند از طرف آنها انجام دهد محدود کنند.

تعریف محدوده ها

شما می توانید محدوده های API خود را با استفاده از Passport::tokensCan روش موجود در boot متد خود تعریف کنید AuthServiceProvider . این tokensCan روش مجموعه‌ای از نام‌های محدوده و توصیف‌های محدوده را می‌پذیرد. شرح محدوده ممکن است هر چیزی باشد که شما بخواهید و در صفحه تایید مجوز برای کاربران نمایش داده می شود:

use Laravel\Passport\Passport;
 
Passport::tokensCan([
'place-orders' => 'Place orders',
'check-status' => 'Check order status',
]);

محدوده پیش فرض

اگر یک کلاینت دامنه خاصی را درخواست نکرد، می‌توانید سرور پاسپورت خود را پیکربندی کنید تا با استفاده از روش، یک محدوده پیش‌فرض به توکن متصل شود setDefaultScope . به طور معمول، شما باید این متد را از boot متد خود فراخوانی کنید AuthServiceProvider :

use Laravel\Passport\Passport;
 
Passport::setDefaultScope([
'check-status',
'place-orders',
]);

اختصاص دامنه به توکن ها

هنگام درخواست کدهای مجوز

هنگام درخواست رمز دسترسی با استفاده از اعطای کد مجوز، مصرف کنندگان باید محدوده مورد نظر خود را به عنوان scope پارامتر رشته پرس و جو مشخص کنند. پارامتر scope باید فهرستی از محدوده‌ها با فاصله محدود باشد:

Route::get('/redirect', function () {
$query = http_build_query([
'client_id' => 'client-id',
'redirect_uri' => 'http://example.com/callback',
'response_type' => 'code',
'scope' => 'place-orders check-status',
]);
 
return redirect('http://your-app.com/oauth/authorize?'.$query);
});

هنگام صدور توکن های دسترسی شخصی

اگر نشانه‌های دسترسی شخصی را با استفاده از روش User مدل صادر می‌کنید createToken ، می‌توانید آرایه دامنه‌های مورد نظر را به عنوان آرگومان دوم به متد ارسال کنید:

$token = $user->createToken('My Token', ['place-orders'])->accessToken;

بررسی محدوده ها

پاسپورت شامل دو میانافزار است که ممکن است برای تأیید اعتبار درخواست ورودی با توکنی استفاده شود که محدوده مشخصی به آن داده شده است. برای شروع، میان افزار زیر را به $routeMiddleware ویژگی فایل خود اضافه کنید app/Http/Kernel.php :

'scopes' => \Laravel\Passport\Http\Middleware\CheckScopes::class,
'scope' => \Laravel\Passport\Http\Middleware\CheckForAnyScope::class,

همه دامنه ها را بررسی کنید

میان‌افزار scopes ممکن است به مسیری اختصاص داده شود تا تأیید کند که رمز دسترسی درخواست ورودی دارای تمام دامنه‌های فهرست شده است:

Route::get('/orders', function () {
// Access token has both "check-status" and "place-orders" scopes...
})->middleware(['auth:api', 'scopes:check-status,place-orders']);

برای هر محدوده بررسی کنید

میان scope افزار ممکن است به مسیری اختصاص داده شود تا تأیید کند که نشانه دسترسی درخواست ورودی حداقل یکی از حوزه های فهرست شده را دارد:

Route::get('/orders', function () {
// Access token has either "check-status" or "place-orders" scope...
})->middleware(['auth:api', 'scope:check-status,place-orders']);

بررسی محدوده ها در یک نمونه توکن

tokenCan هنگامی که یک درخواست احراز هویت توکن دسترسی وارد برنامه شما شد، همچنان می‌توانید با استفاده از روش موجود در User نمونه احراز هویت شده ، بررسی کنید که آیا توکن دارای محدوده مشخصی است :

use Illuminate\Http\Request;
 
Route::get('/orders', function (Request $request) {
if ($request->user()->tokenCan('place-orders')) {
//
}
});

روش های دامنه اضافی

متد scopeIds آرایه ای از همه شناسه ها / نام های تعریف شده را برمی گرداند:

Laravel\Passport\Passport::scopeIds();

متد scopes آرایه ای از تمام محدوده های تعریف شده را به عنوان نمونه های زیر برمی گرداند Laravel\Passport\Scope :

Laravel\Passport\Passport::scopes();

این scopesFor روش آرایه‌ای از Laravel\Passport\Scope نمونه‌های مطابق با شناسه‌ها/نام‌های داده شده را برمی‌گرداند:

Laravel\Passport\Passport::scopesFor(['place-orders', 'check-status']);

شما می توانید تعیین کنید که آیا یک محدوده معین با استفاده از روش تعریف شده است hasScope :

Laravel\Passport\Passport::hasScope('place-orders');

مصرف API خود با جاوا اسکریپت

هنگام ساختن یک API، این می تواند بسیار مفید باشد که بتوانید API خود را از برنامه جاوا اسکریپت خود مصرف کنید. این رویکرد برای توسعه API به برنامه کاربردی شما اجازه می‌دهد تا همان API را که با جهان به اشتراک می‌گذارید، مصرف کند. همان API ممکن است توسط برنامه های کاربردی وب، برنامه های تلفن همراه، برنامه های شخص ثالث و هر SDK که ممکن است در مدیران بسته های مختلف منتشر کنید مصرف شود.

به طور معمول، اگر می خواهید API خود را از برنامه جاوا اسکریپت خود مصرف کنید، باید به صورت دستی یک نشانه دسترسی به برنامه ارسال کنید و آن را با هر درخواست به برنامه خود ارسال کنید. با این حال، Passport شامل یک میان افزار است که می تواند این کار را برای شما انجام دهد. تنها کاری که باید انجام دهید این است که CreateFreshApiToken میان افزار را به web گروه میان افزار خود در app/Http/Kernel.php فایل خود اضافه کنید:

'web' => [
// Other middleware...
\Laravel\Passport\Http\Middleware\CreateFreshApiToken::class,
],

باید اطمینان حاصل کنید که CreateFreshApiToken میان افزار آخرین میان افزار لیست شده در پشته میان افزار شما باشد.

این میان افزار Passport یک laravel_token کوکی به پاسخ های خروجی شما متصل می کند. این کوکی حاوی یک JWT رمزگذاری شده است که پاسپورت از آن برای احراز هویت درخواست های API از برنامه جاوا اسکریپت شما استفاده می کند. اکنون، می‌توانید بدون ارسال صریح نشانه دسترسی، درخواست‌هایی را به API برنامه خود ارسال کنید:

axios.get('/api/user')
.then(response => {
console.log(response.data);
});

سفارشی کردن نام کوکی

در صورت نیاز، می توانید laravel_token نام کوکی را با استفاده از Passport::cookie روش سفارشی کنید. به طور معمول، این متد باید از boot متد شما فراخوانی شود AuthServiceProvider :

/**
* Register any authentication / authorization services.
*
* @return void
*/
public function boot()
{
$this->registerPolicies();
 
Passport::routes();
 
Passport::cookie('custom_name');
}

حفاظت CSRF

هنگام استفاده از این روش احراز هویت، باید اطمینان حاصل کنید که یک هدر توکن معتبر CSRF در درخواست‌های شما گنجانده شده است. داربست پیش‌فرض جاوا اسکریپت لاراول شامل یک نمونه Axios است که به‌طور خودکار از XSRF-TOKEN مقدار کوکی رمزگذاری‌شده برای ارسال X-XSRF-TOKEN هدر در درخواست‌های با منبع مشابه استفاده می‌کند.

X-CSRF-TOKEN اگر بجای ارسال هدر انتخاب کنید X-XSRF-TOKEN ، باید از رمز رمزگذاری نشده ارائه شده توسط استفاده کنید csrf_token() .

مناسبت ها

پاسپورت رویدادها را هنگام صدور توکن های دسترسی و رفرش توکن ها افزایش می دهد. می توانید از این رویدادها برای هرس کردن یا لغو سایر نشانه های دسترسی در پایگاه داده خود استفاده کنید. شما می توانید شنوندگان را به این رویدادها در برنامه خود پیوست کنید EventServiceProvider :

/**
* The event listener mappings for the application.
*
* @var array
*/
protected $listen = [
'Laravel\Passport\Events\AccessTokenCreated' => [
'App\Listeners\RevokeOldTokens',
],
 
'Laravel\Passport\Events\RefreshTokenCreated' => [
'App\Listeners\PruneOldTokens',
],
];

آزمایش کردن

روش پاسپورت actingAs ممکن است برای مشخص کردن کاربر تأیید شده فعلی و همچنین محدوده آن استفاده شود. اولین آرگومان داده شده به actingAs متد، نمونه کاربر است و دومی آرایه ای از دامنه است که باید به توکن کاربر اعطا شود:

use App\User;
use Laravel\Passport\Passport;
 
public function testServerCreation()
{
Passport::actingAs(
factory(User::class)->create(),
['create-servers']
);
 
$response = $this->post('/api/create-server');
 
$response->assertStatus(201);
}

روش پاسپورت actingAsClient ممکن است برای مشخص کردن مشتری تأیید شده فعلی و همچنین محدوده آن استفاده شود. اولین آرگومان ارائه شده به actingAsClient متد، نمونه مشتری است و دومی آرایه ای از دامنه است که باید به توکن مشتری اعطا شود:

use Laravel\Passport\Client;
use Laravel\Passport\Passport;
 
public function testGetOrders()
{
Passport::actingAsClient(
factory(Client::class)->create(),
['check-status']
);
 
$response = $this->get('/api/orders');
 
$response->assertStatus(200);
}