Версія фреймворка: 8.x

Laravel святий

Вступ

Laravel Sanctum пропонує легку систему автентифікації для SPA (додатків на одній сторінці), мобільних додатків та простих API на основі токенів. Sanctum дозволяє кожному користувачеві вашого додатку генерувати кілька маркерів API для свого облікового запису. Цим маркерам можуть бути надані здібності / сфери дії, які визначають, які дії маркерам дозволено виконувати.

Як це працює

Laravel Sanctum існує для вирішення двох окремих проблем.

Маркери API

По-перше, це простий пакет для видачі маркерів API своїм користувачам без ускладнення OAuth. Ця функція натхнена GitHub "маркерами доступу". Наприклад, уявіть, що у "налаштуваннях облікового запису" вашої програми є екран, на якому користувач може генерувати маркер API для свого облікового запису. Ви можете використовувати Sanctum для створення та управління цими маркерами. Як правило, ці маркери мають дуже тривалий термін дії (роки), але користувач може в будь-який час скасувати їх вручну.

Laravel Sanctum пропонує цю функцію, зберігаючи токени API користувача в одній таблиці бази даних та аутентифікуючи вхідні запити черезAuthorizationзаголовок, який повинен містити дійсний маркер API.

Аутентифікація SPA

По-друге, Sanctum існує, щоб запропонувати простий спосіб автентифікації односторінкових програм (SPA), які потребують зв’язку з API, що працює на основі Laravel. Ці SPA можуть існувати в тому ж сховищі, що і ваша програма Laravel, або можуть бути абсолютно окремими сховищами, такими як SPA, створений за допомогою Vue CLI.

Для цієї функції Sanctum не використовує жодних жетонів. Натомість Sanctum використовує вбудовані служби аутентифікації сеансів на основі файлів cookie Laravel. Це забезпечує переваги захисту CSRF, аутентифікації сеансу, а також захищає від витоку облікових даних автентифікації через XSS. Sanctum намагатиметься автентифікуватись за допомогою файлів cookie лише тоді, коли вхідний запит надходить із вашого власного інтерфейсу SPA.

Цілком чудово використовувати Sanctum лише для автентифікації маркера API або лише для аутентифікації SPA. Те, що ви використовуєте Sanctum, не означає, що вам потрібно використовувати обидві функції, які він пропонує.

Встановлення

Ви можете встановити Laravel Sanctum через Composer:

composer require laravel/sanctum

Далі слід опублікувати файли конфігурації та міграції Sanctum за допомогоюvendor:publishartisan командування.sanctumфайл конфігурації буде розміщений у вашомуconfigкаталог:

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

Нарешті, слід запустити міграції бази даних. Sanctum створить одну таблицю бази даних, в якій зберігатимуться маркери API:

php artisan migrate

Далі, якщо ви плануєте використовувати Sanctum для аутентифікації SPA, вам слід додати Middlware Sanctum до вашогоapiгрупа проміжного програмного забезпечення у вашомуapp/Http/Kernel.phpфайл:

'api' => [
    \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
    'throttle:api',
    \Illuminate\Routing\Middleware\SubstituteBindings::class,
],

Налаштування міграції

Якщо ви не збираєтеся використовувати стандартні міграції Sanctum, вам слід зателефонувати доSanctum::ignoreMigrationsметод уregisterметод вашогоAppServiceProvider. Ви можете експортувати міграції за замовчуванням за допомогоюphp artisan vendor:publish --tag=sanctum-migrations.

Конфігурація

Заміна стандартних моделей

Ви можете продовжитиPersonalAccessTokenмодель, що використовується внутрішньо Sanctum:

use Laravel\Sanctum\PersonalAccessToken as SanctumPersonalAccessToken;

class PersonalAccessToken extends SanctumPersonalAccessToken
{
    // ...
}

Тоді ви можете доручити Sanctum використовувати вашу власну модель черезusePersonalAccessTokenModelметод, наданий Sanctum. Як правило, ви повинні викликати цей метод уbootметоду одного з ваших постачальників послуг:

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

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

Аутентифікація маркера API

Не слід використовувати маркери API для автентифікації власного власного SPA. Натомість використовуйте вбудований SanctumSPA аутентифікація.

Видача токенів API

Sanctum дозволяє видавати маркери API / маркери особистого доступу, які можуть використовуватися для автентифікації запитів API. Під час надсилання запитів за допомогою маркерів API, маркер повинен бути включений уAuthorizationзаголовок як aBearerмаркер.

Щоб розпочати видачу токенів для користувачів, ваша модель Користувач повинна використовуватиHasApiTokensриса:

use Laravel\Sanctum\HasApiTokens;

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

Щоб видати маркер, ви можете використовуватиcreateTokenметод.createTokenметод повертає aLaravel\Sanctum\NewAccessTokenекземпляр. Маркери API хешуються за допомогою хешування SHA-256 перед збереженням у вашій базі даних, але ви можете отримати доступ до простого текстового значення маркера заplainTextTokenвласністьNewAccessTokenекземпляр. Ви повинні показати це значення користувачеві одразу після створення маркера:

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

return $token->plainTextToken;

Ви можете отримати доступ до всіх токенів користувача за допомогоюtokensКрасномовні відносини, наданіHasApiTokensриса:

foreach ($user->tokens as $token) {
    //
}

Можливості жетонів

Sanctum дозволяє призначати маркерам "здібності", подібні до "областей" OAuth. Ви можете передати масив рядкових здібностей як другий аргумент вcreateTokenметод:

return $user->createToken('token-name', ['server:update'])->plainTextToken;

При обробці вхідного запиту, автентифікованого Sanctum, ви можете визначити, чи має маркер задану здатність, використовуючиtokenCanметод:

if ($user->tokenCan('server:update')) {
    //
}
Для зручності,tokenCanметод завжди повертаєтьсяtrueякщо вхідний аутентифікований запит надійшов від вашого основного SPA, і ви використовуєте вбудований SanctumSPA аутентифікація.

Захист маршрутів

Щоб захистити маршрути, щоб усі вхідні запити мали бути автентифікованими, слід додати файлsanctumзахист автентифікації до ваших маршрутів API у вашомуroutes/api.phpфайл. Цей охоронець гарантує, що вхідні запити аутентифікуються як аутентифіковані запити з вашого SPA або містять дійсний заголовок маркера API, якщо запит надходить від третьої сторони:

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

Відкликання жетонів

Ви можете "відкликати" маркери, видаливши їх зі своєї бази даних за допомогоюtokensвідносини, які забезпечуютьсяHasApiTokensриса:

// 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();

Аутентифікація SPA

Sanctum існує, щоб запропонувати простий спосіб автентифікації односторінкових програм (SPA), які потребують зв’язку з API, що працює на основі Laravel. Ці SPA можуть існувати в тому ж сховищі, що і ваша програма Laravel, або можуть бути абсолютно окремими сховищами, такими як SPA, створений за допомогою Vue CLI.

Для цієї функції Sanctum не використовує жодних жетонів. Натомість Sanctum використовує вбудовані служби аутентифікації сеансів на основі файлів cookie Laravel. Це забезпечує переваги захисту CSRF, аутентифікації сеансу, а також захищає від витоку облікових даних автентифікації через XSS. Sanctum намагатиметься автентифікуватись за допомогою файлів cookie лише тоді, коли вхідний запит надходить із вашого власного інтерфейсу SPA.

Для автентифікації ваші SPA та API мають спільний домен верхнього рівня. Однак вони можуть розміщуватися на різних субдоменах.

Конфігурація

Налаштування основних доменів

По-перше, вам слід налаштувати, з яких доменів ваш SPA буде робити запити. Ви можете налаштувати ці домени за допомогоюstatefulваріант конфігурації у вашомуsanctumфайл конфігурації. Цей параметр конфігурації визначає, які домени підтримуватимуть аутентифікацію, що відповідає стану, за допомогою файлів cookie сеансу Laravel під час надсилання запитів до вашого API.

Якщо ви отримуєте доступ до своєї програми за URL-адресою, яка включає порт (127.0.0.1:8000), ви повинні переконатися, що ви включили номер порту до домену.

Санктум Посуд

Далі слід додати Middlware Sanctum до вашогоapiгрупа проміжного програмного забезпечення у вашомуapp/Http/Kernel.phpфайл. Це Middlware відповідає за те, щоб вхідні запити з вашого SPA могли автентифікуватися за допомогою сеансових файлів cookie Laravel, дозволяючи при цьому запитам від третіх сторін або мобільних додатків проводити автентифікацію за допомогою маркерів API:

use Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful;

'api' => [
    EnsureFrontendRequestsAreStateful::class,
    'throttle:api',
    \Illuminate\Routing\Middleware\SubstituteBindings::class,
],

CORS & Cookies

Якщо у вас виникають проблеми з автентифікацією вашої програми із SPA, яка виконується на окремому субдомені, ви, ймовірно, неправильно налаштували параметри CORS (спільне використання ресурсів) або сеансові файли cookie.

Ви повинні переконатися, що конфігурація CORS вашої програми повертає файлAccess-Control-Allow-Credentialsзаголовок зі значеннямTrueвстановившиsupports_credentialsу вашому додаткуcorsфайл конфігурації доtrue.

Крім того, слід увімкнутиwithCredentialsваріант на вашому глобальномуaxiosекземпляр. Як правило, це слід виконувати у вашомуresources/js/bootstrap.jsфайл:

axios.defaults.withCredentials = true;

Нарешті, слід переконатись, що конфігурація доменного файлу cookie сеансу програми підтримує будь-який субдомен вашого кореневого домену. Ви можете зробити це, додавши домену префікс ведучого.в межах вашогоsessionфайл конфігурації:

'domain' => '.domain.com',

Автентифікація

Для автентифікації вашого SPA, сторінка входу вашого SPA повинна спочатку зробити запит до/sanctum/csrf-cookieмаршрут для ініціалізації захисту CSRF для програми:

axios.get('/sanctum/csrf-cookie').then(response => {
    // Login...
});

Під час цього запиту Laravel встановитьXSRF-TOKENфайл cookie, що містить поточний маркер CSRF. Потім цей маркер повинен бути переданий уX-XSRF-TOKENзаголовок на наступні запити, які бібліотеки, такі як Axios та Angular HttpClient, автоматично роблять для вас.

Після ініціалізації захисту CSRF ви повинні зробити aPOSTзапит до типового Laravel/loginмаршрут. Це/loginмаршрут може бути наданийlaravel/jetstreamриштування для автентифікаціїпакет.

Якщо запит на вхід буде успішним, ви пройдете автентифікацію, а наступні запити до ваших маршрутів API будуть автоматично автентифіковані за допомогою сеансового файлу cookie, який сервер Laravel видав вашому клієнту.

Ви можете написати своє власне/loginкінцева точка; однак вам слід переконатись, що він автентифікує користувача за допомогою стандарту,послуги аутентифікації на основі сеансів, які надає Laravel.

Захист маршрутів

Щоб захистити маршрути, щоб усі вхідні запити мали бути автентифікованими, слід додати файлsanctumзахист автентифікації до ваших маршрутів API у вашомуroutes/api.phpфайл. Цей охоронець гарантує, що вхідні запити аутентифікуються як аутентифіковані запити з вашого SPA або містять дійсний заголовок маркера API, якщо запит надходить від третьої сторони:

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

Авторизація приватних трансляційних каналів

Якщо ваш SPA потребує автентифікації зприватні / присутні канали мовлення, вам слід розміститиBroadcast::routesвиклик методу у вашомуroutes/api.phpфайл:

Broadcast::routes(['middleware' => ['auth:sanctum']]);

Далі, для того, щоб запити авторизації Pusher мали успіх, вам потрібно буде надати спеціальний Pusherauthorizerпри ініціалізаціїLaravel Echo. Це дозволяє вашій програмі налаштувати Pusher на використанняaxiosекземпляр, тобтоналежним чином налаштовано для міждоменних запитів:

window.Echo = new Echo({
    broadcaster: "pusher",
    cluster: process.env.MIX_PUSHER_APP_CLUSTER,
    encrypted: true,
    key: process.env.MIX_PUSHER_APP_KEY,
    authorizer: (channel, options) => {
        return {
            authorize: (socketId, callback) => {
                axios.post('/api/broadcasting/auth', {
                    socket_id: socketId,
                    channel_name: channel.name
                })
                .then(response => {
                    callback(false, response.data);
                })
                .catch(error => {
                    callback(true, error);
                });
            }
        };
    },
})

Аутентифікація мобільних додатків

Ви можете використовувати маркери Sanctum для автентифікації запитів вашого мобільного додатка до вашого API. Процес автентифікації запитів мобільних додатків подібний до автентифікації сторонніх запитів API; однак є невеликі відмінності в тому, як ви будете видавати маркери API.

Видача токенів API

Для початку створіть маршрут, який приймає електронну адресу користувача / ім’я користувача, пароль та ім’я пристрою, а потім обмінює ці облікові дані на новий маркер Sanctum. Кінцева точка поверне простотекстовий маркер Sanctum, який потім може бути збережений на мобільному пристрої та використаний для додаткових запитів API:

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

Route::post('/sanctum/token', function (Request $request) {
    $request->validate([
        'email' => 'required|email',
        'password' => 'required',
        'device_name' => '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($request->device_name)->plainTextToken;
});

Коли мобільний пристрій використовує маркер для надсилання запиту API до вашої програми, він повинен передати маркер уAuthorizationзаголовок як aBearerмаркер.

Під час випуску токенів для мобільного додатку ви також можете вказатисимволічні здібності

Захист маршрутів

Як було задокументовано раніше, ви можете захистити маршрути, щоб усі вхідні запити повинні бути автентифіковані, додавшиsanctumавтентифікаційний охоронець маршрутів. Зазвичай ви прикріплюєте цю охорону до маршрутів, визначених у вашомуroutes/api.phpфайл:

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

Відкликання жетонів

Щоб дозволити користувачам відкликати маркери API, видані на мобільні пристрої, ви можете вказати їх за іменами, разом із кнопкою «Відкликати», у розділі «Налаштування облікового запису» в інтерфейсі веб-програми. Коли користувач натискає кнопку "Відкликати", ви можете видалити маркер з бази даних. Пам'ятайте, ви можете отримати доступ до маркерів API користувача черезtokensвідносини, передбаченіHasApiTokensриса:

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

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

Тестування

Під час тестуванняSanctum::actingAsметод може бути використаний для автентифікації користувача та вказівки, які можливості надаються їх токену:

use App\Models\User;
use Laravel\Sanctum\Sanctum;

public function test_task_list_can_be_retrieved()
{
    Sanctum::actingAs(
        User::factory()->create(),
        ['view-tasks']
    );

    $response = $this->get('/api/task');

    $response->assertOk();
}

Якщо ви хочете надати маркеру всі здібності, ви повинні включити*у списку здібностей, наданомуactingAsметод:

Sanctum::actingAs(
    User::factory()->create(),
    ['*']
);