Документация Laravel 10.x
Здесь ты найдешь сниппеты по Laravel и полезные советы по веб-разработке.
Laravel Sanctum предоставляет легковесную систему аутентификации для одностраничных приложений (SPA), мобильных приложений и простых API на основе токенов. Sanctum позволяет каждому пользователю вашего приложения создавать несколько API-токенов для своей учетной записи. Этим токенам можно предоставлять различные возможности/области, которые указывают, какие действия разрешены с использованием этих токенов.
Laravel Sanctum существует для решения двух различных задач. Давайте обсудим каждую из них, прежде чем погрузиться в библиотеку глубже.
Во-первых, Sanctum - это простой пакет, который можно использовать для выдачи API-токенов вашим пользователям без сложности OAuth. Эта функция вдохновлена GitHub и другими приложениями, которые выдают "персональные токены доступа". Например, представьте себе, что в "настройках учетной записи" вашего приложения есть экран, где пользователь может создать API-токен для своей учетной записи. Вы можете использовать Sanctum для создания и управления этими токенами. Этим токенам обычно устанавливается очень долгий срок действия (годы), но их можно вручную отозвать пользователем в любое время.
Laravel Sanctum предоставляет эту функцию, сохраняя токены API пользователя в одной таблице базы данных и аутентифицируя входящие HTTP-запросы через заголовок Authorization
, который должен содержать действительный токен API.
Во-вторых, Sanctum существует, чтобы предложить простой способ аутентификации одностраничных приложений (SPA), которые должны взаимодействовать с API, созданным на Laravel. Эти SPA могут существовать в одном репозитории с вашим приложением Laravel или быть полностью отдельным репозиторием, например SPA, созданное с использованием Vue CLI или приложение Next.js.
Для этой функции Sanctum не использует токены. Вместо этого Sanctum использует встроенные в Laravel сеансовые службы аутентификации на основе куки. Обычно Sanctum использует страж аутентификации Laravel web
для достижения этой цели. Это обеспечивает защиту от CSRF, аутентификацию сеанса, а также защиту от утечки учетных данных аутентификации через XSS.
Sanctum будет пытаться аутентифицироваться с использованием куки только тогда, когда входящий запрос исходит из вашего собственного SPA-фронтенда. Когда Sanctum анализирует входящий HTTP-запрос, он сначала проверит наличие аутентификационной куки и, если ее нет, Sanctum затем будет искать действительный токен API в заголовке Authorization
.
Полностью допустимо использовать Sanctum только для аутентификации по API-токенам или только для аутентификации SPA. Просто потому, что вы используете Sanctum, не обязательно использовать обе предлагаемые функции.
В самых последних версиях Laravel уже включен Laravel Sanctum. Однако, если файл
composer.json
вашего приложения не содержитlaravel/sanctum
, вы можете следовать инструкциям по установке ниже.
Вы можете установить Laravel Sanctum с помощью менеджера пакетов Composer:
composer require laravel/sanctum
Затем вы должны опубликовать конфигурацию Sanctum и файлы миграции с использованием команды Artisan vendor:publish
. Файл конфигурации sanctum
будет помещен в каталог config
вашего приложения:
php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"
Наконец, вы должны выполнить миграции базы данных. Sanctum создаст одну таблицу базы данных для хранения токенов API:
php artisan migrate
Далее, если вы планируете использовать Sanctum для аутентификации SPA, вы должны добавить промежуточное ПО Sanctum в группу промежуточного ПО api
в файле app/Http/Kernel.php
вашего приложения:
'api' => [ \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class, \Illuminate\Routing\Middleware\ThrottleRequests::class.':api', \Illuminate\Routing\Middleware\SubstituteBindings::class,],
Если вы не собираетесь использовать стандартные миграции Sanctum, вы должны вызвать метод Sanctum::ignoreMigrations
в методе register
вашего класса App\Providers\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\Sanctum\PersonalAccessToken;use Laravel\Sanctum\Sanctum; /** * Загрузка любых служб приложения. */public function boot(): void{ Sanctum::usePersonalAccessTokenModel(PersonalAccessToken::class);}
Не следует использовать API-токены для аутентификации собственных SPA первой стороны. Вместо этого используйте встроенные возможности аутентификации SPA Sanctum.
Sanctum позволяет выдавать токены API / персональные токены доступа, которые можно использовать для аутентификации запросов API к вашему приложению. При выполнении запросов с использованием API-токенов токен должен включаться в заголовок Authorization
как токен типа Bearer
.
Для начала выдачи токенов пользователям ваша модель User должна использовать трейт Laravel\Sanctum\HasApiTokens
:
use Laravel\Sanctum\HasApiTokens; class User extends Authenticatable{ use HasApiTokens, HasFactory, Notifiable;}
Для выдачи токена вы можете использовать метод createToken
. Метод createToken
возвращает экземпляр Laravel\Sanctum\NewAccessToken
. API-токены хешируются с использованием хеширования SHA-256 перед сохранением в базе данных, но вы можете получить значение токена в открытом виде, используя свойство plainTextToken
экземпляра NewAccessToken
. Вы должны отображать это значение пользователю сразу после создания токена:
use Illuminate\Http\Request; Route::post('/tokens/create', function (Request $request) { $token = $request->user()->createToken($request->token_name); return ['token' => $token->plainTextToken];});
Вы можете получить доступ ко всем токенам пользователя с использованием отношения Eloquent 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')) { // ...}
Sanctum также включает два промежуточных ПО, которые могут использоваться для проверки того, что входящий запрос аутентифицирован токеном, которому предоставлена определенная возможность. Для начала добавьте следующие промежуточные ПО в свойство $middlewareAliases
файла app/Http/Kernel.php
вашего приложения:
'abilities' => \Laravel\Sanctum\Http\Middleware\CheckAbilities::class,'ability' => \Laravel\Sanctum\Http\Middleware\CheckForAnyAbility::class,
Промежуточное ПО abilities
может быть присвоено маршруту для проверки того, что токен входящего запроса имеет все перечисленные возможности:
Route::get('/orders', function () { // Токен имеет как возможность "check-status", так и "place-orders"...})->middleware(['auth:sanctum', 'abilities:check-status,place-orders']);
Промежуточное ПО ability
может быть присвоено маршруту для проверки того, что токен входящего запроса имеет как минимум одну из перечисленных возможностей:
Route::get('/orders', function () { // Токен имеет возможность "check-status" или "place-orders"...})->middleware(['auth:sanctum', 'ability:check-status,place-orders']);
Для удобства метод tokenCan
всегда будет возвращать true
, если аутентифицированный входящий запрос был от вашего SPA первой стороны и вы используете встроенную аутентификацию SPA Sanctum.
Однако это не обязательно означает, что ваше приложение должно разрешать пользователю выполнять действие. Обычно ваши политики авторизации будут определять, предоставлено ли разрешение на выполнение действий для токена, а также проверять, должен ли сам объект пользователя иметь право на выполнение действия.
Например, если мы представим приложение, управляющее серверами, это может означать проверку того, разрешен ли токен для обновления серверов и принадлежит ли сервер пользователю:
return $request->user()->id === $server->user_id && $request->user()->tokenCan('server:update')
Изначально может показаться странным разрешение вызова метода tokenCan
и всегда возвращение true
для запросов, инициированных из пользовательского интерфейса первой стороны; однако удобно предполагать наличие API-токена и возможность его проверки с помощью метода tokenCan
. Приняв такой подход, вы всегда можете вызывать метод tokenCan
в политиках авторизации вашего приложения, не беспокоясь о том, был ли запрос инициирован из пользовательского интерфейса вашего приложения или же им был инициирован потребителем API третьей стороны.
Для защиты маршрутов так, чтобы все входящие запросы требовали аутентификации, вы должны присоединить страж аутентификации sanctum
к вашим защищенным маршрутам в файлах маршрутов routes/web.php
и routes/api.php
. Этот страж обеспечит аутентификацию входящих запросов либо как аутентифицированных с использованием сессионной аутентификации с помощью куки, либо с содержанием действительного заголовка токена API, если запрос поступает от третьей стороны.
Возможно, вы задаетесь вопросом, почему мы предлагаем аутентифицировать маршруты в файле routes/web.php
вашего приложения с использованием стража sanctum
. Помните, что Sanctum сначала попытается аутентифицировать входящие запросы с использованием типичной сессионной аутентификации Laravel. Если этой куки нет, то Sanctum попытается аутентифицировать запрос с использованием токена в заголовке Authorization
запроса. Кроме того, аутентификация всех запросов с использованием Sanctum гарантирует, что мы всегда можем вызывать метод tokenCan
для текущего аутентифицированного экземпляра пользователя:
use Illuminate\Http\Request; Route::middleware('auth:sanctum')->get('/user', function (Request $request) { return $request->user();});
Вы можете "отозвать" токены, удалив их из вашей базы данных с использованием отношения tokens
, предоставляемого трейтом Laravel\Sanctum\HasApiTokens
:
// Отзыв всех токенов...$user->tokens()->delete(); // Отзыв токена, использованного для аутентификации текущего запроса...$request->user()->currentAccessToken()->delete(); // Отзыв конкретного токена...$user->tokens()->where('id', $tokenId)->delete();
По умолчанию токены Sanctum никогда не истекают и могут быть аннулированы только путем отзыва токена. Однако, если вы хотите настроить время истечения токенов API вашего приложения, вы можете сделать это с помощью опции конфигурации expiration
, определенной в конфигурационном файле sanctum
вашего приложения. Эта опция конфигурации определяет количество минут, через которое выданный токен будет считаться истекшим:
'expiration' => 525600,
Если вы настроили время истечения токена для вашего приложения, вы также можете запланировать задачу для очистки истекших токенов вашего приложения. К счастью, Sanctum включает в себя команду Artisan sanctum:prune-expired
, которую вы можете использовать для этого. Например, вы можете настроить запланированные задачи для удаления всех записей о токенах, которые истекли по крайней мере за 24 часа:
$schedule->command('sanctum:prune-expired --hours=24')->daily();
Sanctum также существует для обеспечения простого способа аутентификации одностраничных приложений (SPA), которым необходимо взаимодействовать с API, работающим на Laravel. Эти SPA могут существовать в том же репозитории, что и ваше приложение Laravel, или быть полностью отдельным репозиторием.
Для этой функции Sanctum не использует токены никакого рода. Вместо этого Sanctum использует встроенные в Laravel сессионные службы аутентификации на основе куки. Такой подход к аутентификации обеспечивает преимущества защиты от CSRF, сессионной аутентификации, а также защиты от утечки учетных данных аутентификации через XSS.
Для аутентификации ваш SPA и API должны использовать одинаковый домен верхнего уровня. Однако они могут находиться на разных поддоменах. Кроме того, убедитесь, что вы отправляете заголовок
Accept: application/json
и либо заголовокReferer
, либоOrigin
с вашим запросом.
В первую очередь, вам следует настроить домены, с которых ваше SPA будет делать запросы. Вы можете настроить эти домены с использованием опции конфигурации stateful
в вашем файле конфигурации sanctum
. Эта настройка определяет, какие домены будут поддерживать "состоянийную" аутентификацию с использованием сессионных куки Laravel при выполнении запросов к вашему API.
Если вы получаете доступ к своему приложению через URL, который включает порт (
127.0.0.1:8000
), убедитесь, что вы включили номер порта вместе с доменом.
Затем вы должны добавить промежуточное ПО Sanctum к группе промежуточных ПО api
в вашем файле app/Http/Kernel.php
. Это промежуточное ПО отвечает за обеспечение того, чтобы входящие запросы от вашего SPA могли аутентифицироваться с использованием сессионных куки Laravel, при этом разрешая запросы от третьих сторон или мобильных приложений аутентифицироваться с использованием токенов API:
'api' => [ \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class, \Illuminate\Routing\Middleware\ThrottleRequests::class.':api', \Illuminate\Routing\Middleware\SubstituteBindings::class,],
Если у вас возникли проблемы с аутентификацией в вашем приложении из SPA, выполняющегося на отдельном поддомене, вероятно, вы неправильно настроили CORS (Cross-Origin Resource Sharing) или параметры сессионных куки.
Убедитесь, что конфигурация CORS вашего приложения возвращает заголовок Access-Control-Allow-Credentials
со значением True
. Это можно сделать, установив опцию supports_credentials
в файле конфигурации вашего приложения config/cors.php
в значение true
.
Кроме того, активируйте опцию withCredentials
в глобальном экземпляре axios
вашего приложения. Обычно это следует выполнять в файле resources/js/bootstrap.js
. Если вы не используете Axios для выполнения HTTP-запросов из вашего фронтенда, вы должны выполнить аналогичную конфигурацию для своего собственного HTTP-клиента:
axios.defaults.withCredentials = true;
Наконец, убедитесь, что конфигурация домена куки сессии вашего приложения поддерживает любой поддомен вашего корневого домена. Вы можете сделать это, предварив домен ведущей .
в файле конфигурации сессии вашего приложения config/session.php
:
'domain' => '.domain.com',
Для аутентификации вашего SPA страница "входа" SPA должна сначала отправить запрос к конечной точке /sanctum/csrf-cookie
, чтобы инициализировать защиту от CSRF для приложения:
axios.get('/sanctum/csrf-cookie').then(response => { // Логин...});
Во время этого запроса Laravel установит куки XSRF-TOKEN
, содержащую текущий токен CSRF. Этот токен должен затем передаваться в заголовке X-XSRF-TOKEN
при последующих запросах, что некоторые библиотеки HTTP-клиентов, такие как Axios и Angular HttpClient, делают автоматически. Если ваша библиотека HTTP-клиента на JavaScript не устанавливает значение автоматически, вам нужно будет вручную установить заголовок X-XSRF-TOKEN
, чтобы сопоставить значение куки XSRF-TOKEN
, установленной этим маршрутом.
После инициализации защиты от CSRF следует выполнить POST
-запрос к маршруту /login
вашего Laravel-приложения. Этот маршрут /login
можно реализовать вручную или с использованием безголового пакета аутентификации, такого как Laravel Fortify.
Если запрос на вход прошел успешно, вы будете аутентифицированы, и последующие запросы к маршрутам вашего приложения автоматически будут аутентифицированы с использованием сессионной куки, которую выдает ваше клиентское приложение. Кроме того, поскольку ваше приложение уже отправило запрос к маршруту /sanctum/csrf-cookie
, последующие запросы должны автоматически получать защиту от CSRF, при условии, что ваш JavaScript HTTP-клиент отправляет значение куки XSRF-TOKEN
в заголовке X-XSRF-TOKEN
.
Конечно же, если сеанс пользователя истек из-за отсутствия активности, последующие запросы к Laravel-приложению могут получать ответ HTTP с ошибкой 401 или 419. В этом случае вы должны перенаправить пользователя на страницу входа вашего SPA.
Вы можете написать собственный конечный пункт
/login
; однако убедитесь, что он аутентифицирует пользователя с использованием стандартных сеансовых служб аутентификации, предоставляемых Laravel. Обычно это означает использование стража аутентификации Laravelweb
.
Для защиты маршрутов так, чтобы все входящие запросы требовали аутентификации, вы должны присоединить страж аутентификации sanctum
к вашим маршрутам API в файле routes/api.php
. Этот страж обеспечит аутентификацию входящих запросов либо как аутентифицированных, выполняемых вашим SPA, либо с действительным заголовком токена API, если запрос поступает от третьей стороны:
use Illuminate\Http\Request; Route::middleware('auth:sanctum')->get('/user', function (Request $request) { return $request->user();});
Если вашему SPA необходимо аутентифицироваться с частными / присутствующими каналами вещания, разместите вызов метода Broadcast::routes
в вашем файле routes/api.php
:
Broadcast::routes(['middleware' => ['auth:sanctum']]);
Затем, чтобы запросы на авторизацию Pusher'a были успешными, вам нужно предоставить пользовательский authorizer
Pusher'a при инициализации Laravel Echo. Это позволяет вашему приложению настроить Pusher для использования экземпляра axios
, который правильно настроен для междоменных запросов:
window.Echo = new Echo({ broadcaster: "pusher", cluster: import.meta.env.VITE_PUSHER_APP_CLUSTER, encrypted: true, key: import.meta.env.VITE_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.
Для начала создайте маршрут, который принимает электронную почту / имя пользователя пользователя, пароль и имя устройства, затем обменивает эти учетные данные на новый токен Sanctum. "Имя устройства", предоставленное этому конечному пункту, предназначено исключительно для информационных целей и может быть любым значением, которое вы выберете. В целом значение имени устройства должно быть именем, которое пользователь узнает, например "iPhone 12 Нуно".
Обычно запрос на конечную точку токена выполняется со страницы "входа" вашего мобильного приложения. Эта конечная точка вернет токен API в виде обычного текста, который затем может быть сохранен на мобильном устройстве и использован для выполнения дополнительных запросов к 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
как токен Bearer
.
При выдаче токенов для мобильного приложения вы можете также указать возможности токена.
Как было ранее описано, вы можете защитить маршруты так, чтобы все входящие запросы должны были быть аутентифицированы, присоединив страж аутентификации sanctum
к маршрутам:
Route::middleware('auth:sanctum')->get('/user', function (Request $request) { return $request->user();});
Чтобы пользователи могли отозвать API-токены, выданные для мобильных устройств, вы можете перечислить их по именам, вместе с кнопкой "Отозвать", в разделе "Настройки учетной записи" вашего веб-приложения. Когда пользователь нажимает кнопку "Отозвать", вы можете удалить токен из базы данных. Помните, что вы можете получить доступ к токенам API пользователя через отношение tokens
, предоставляемое трейтом Laravel\Sanctum\HasApiTokens
:
// Отзыв всех токенов...$user->tokens()->delete(); // Отзыв конкретного токена...$user->tokens()->where('id', $tokenId)->delete();
При тестировании метод Sanctum::actingAs
можно использовать для аутентификации пользователя и указания, какие возможности должен получить его токен:
use App\Models\User;use Laravel\Sanctum\Sanctum; public function test_task_list_can_be_retrieved(): void{ Sanctum::actingAs( User::factory()->create(), ['view-tasks'] ); $response = $this->get('/api/task'); $response->assertOk();}
Если вы хотите предоставить все возможности токену, вы должны включить *
в список возможностей, предоставленный методу actingAs
:
Sanctum::actingAs( User::factory()->create(), ['*']);