Пакет Laravel Sanctum
11.x
.
Почему это важно?
- Введение
- Как это работает
- Установка
- Конфигурирование
- Переопределение моделей по умолчанию
- Аутентификация токена API
- Выдача токенов API
- Полномочия токена
- Защита маршрутов
- Отзыв токенов
- Срок действия токена
- Аутентификация SPA
- Конфигурирование SPA
- Выполнение аутентификации SPA
- Защита маршрутов SPA
- Авторизация частных каналов вещания
- Аутентификация мобильного приложения
- Выдача токенов API мобильного приложения
- Защита маршрутов API мобильного приложения
- Отзыв токенов API мобильного приложения
- Тестирование
Введение
Laravel Sanctum предлагает легковесную систему аутентификации для SPA (одностраничных приложений), мобильных приложений и простых API на основе токенов. Sanctum позволяет каждому пользователю вашего приложения создавать несколько токенов API для своей учетной записи. Этим токенам могут быть предоставлены полномочия / области, которые определяют, какие действия токенам разрешено выполнять.
Как это работает
Laravel Sanctum существует для решения двух отдельных задач. Давайте обсудим каждую из них, прежде чем углубиться в изучение пакета.
Краткая информация о токенах API
Во-первых, Sanctum – это простой пакет, который вы можете использовать для выдачи токенов API своим пользователям без осложнений с OAuth. Этот функционал вдохновлен GitHub и другими приложениями, которые выдают «токены личного доступа». Например, представьте, что в «настройках учетной записи» вашего приложения есть экран, на котором пользователь может сгенерировать токен API для своей учетной записи. Вы можете использовать Sanctum для создания этих токенов и управления ими. Эти токены обычно имеют очень длительный срок действия (годы), но могут быть отозваны пользователем самостоятельно в любое время.
Laravel Sanctum предлагает этот функционал через сохранение токенов API пользователя в единой таблице базы данных и аутентифицируя входящие HTTP-запросы через заголовок Authorization
, который должен содержать действительный токен API.
Краткая информация об аутентификации SPA
Во-вторых, Sanctum также обеспечивает простой метод аутентификации одностраничных приложений (SPA), взаимодействующих с API Laravel. Эти SPA могут существовать в том же репозитории, что и ваше приложение Laravel, или могут быть полностью отдельным репозиторием, например SPA, созданные с помощью Vue CLI или приложения Next.js.
Для этого функционала Sanctum не использует никаких токенов. Вместо этого Sanctum использует встроенные в Laravel службы аутентификации сессии на основе файлов cookie. Обычно для этого Sanctum использует охранника web
аутентификации Laravel. Это обеспечивает преимущества защиты от CSRF, аутентификации сессии, а также защищает от утечки учетных данных аутентификации через XSS.
Sanctum будет пытаться аутентифицироваться с помощью файлов cookie только тогда, когда входящий запрос исходит от вашей собственной клиентской части SPA. Когда Sanctum проверяет входящий HTTP-запрос, он сначала проверяет файл cookie аутентификации, а если он отсутствует, то Sanctum проверяет заголовок Authorization
на наличие действительного токена API.
Совершенно нормально использовать Sanctum только для аутентификации токена API или только для аутентификации SPA. Тот факт, что вы используете Sanctum, не означает, что вы должны использовать оба функционала, которые он предлагает.
Установка
Последние версии Laravel уже включают Laravel Sanctum. Однако если файл
composer.json
вашего приложения не содержитlaravel/sanctum
, вы можете добавить его вручную по приведенным ниже инструкциям.
Вы можете установить Laravel Sanctum через менеджер пакетов Composer:
composer require laravel/sanctum
Затем, вы должны опубликовать файлы конфигурации и миграции Sanctum с помощью команды vendor:publish
Artisan. Файл конфигурации 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
Вы не должны использовать токены API для аутентификации собственного SPA. Вместо этого используйте функционал аутентификации SPA Sanctum.
Выдача токенов API
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 позволяет вам назначать «полномочия» (abilities) токенам. Полномочия служат той же цели, что и «права доступа» OAuth Scopes. Вы можете передать массив, содержащий строковые ключи полномочий, в качестве второго аргумента методу 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 () {
// У токена есть возможности как для проверки статуса, так и для размещения заказов...
})->middleware(['auth:sanctum', 'abilities:check-status,place-orders']);
Посредник ability
может быть назначен маршруту для проверки того, что токен входящего запроса имеет “по крайней мере одну” из перечисленных возможностей:
Route::get('/orders', function () {
// Токен имеет возможность "проверить статус" или "разместить заказы"...
})->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.
Защита маршрутов
Чтобы защитить маршруты через обязательную аутентификацию входящих запросов, вы должны назначить охранника (guard) аутентификации sanctum
вашим защищаемым маршрутам в файлах маршрутов routes/web.php
и routes/api.php
. Этот охранник гарантирует, что входящие запросы аутентифицируются либо как запросы с cookie, если запрос поступает от веб-страницы, сформированной Laravel, либо как запросы с токеном API, если запрос поступает от внешнего SPA- или мобильного приложения.
Вам может быть интересно, почему мы предлагаем вам аутентифицировать маршруты в файле routes/web.php
вашего приложения, используя охранник sanctum
. Помните, что Sanctum сначала попытается аутентифицировать входящие запросы, используя типичный файл cookie аутентификации сессии Laravel. Если этот файл cookie отсутствует, то 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,
Если вы хотите указать время истечения каждого токена отдельно, вы можете сделать это, передав время истечения в качестве третьего аргумента методу createToken
:
return $user->createToken(
'token-name', ['*'], now()->addWeek()
)->plainTextToken;
Если вы настроили время истечения токена для вашего приложения, вы также можете запланировать задачу для очистки истекших токенов вашего приложения. К счастью, Sanctum включает в себя команду Artisan sanctum:prune-expired
, которую вы можете использовать для выполнения этой задачи. Например, вы можете настроить запланированную задачу для удаления всех записей об истекших токенах в базе данных, которые были истекшие как минимум 24 часа:
$schedule->command('sanctum:prune-expired --hours=24')->daily();
Аутентификация SPA
Sanctum также обеспечивает простой метод аутентификации одностраничных приложений (SPA), взаимодействующих с API Laravel. Эти SPA могут существовать в том же репозитории, что и ваше приложение Laravel, или могут быть полностью отдельным репозиторием.
Для этого функционала Sanctum не использует никаких токенов. Вместо этого Sanctum использует встроенные в Laravel службы аутентификации сессии на основе файлов Cookies. Такой подход к аутентификации обеспечивает преимущества защиты от CSRF, аутентификации сессии, а также защищает от утечки учетных данных аутентификации через XSS.
Для аутентификации вашего одностраничного приложения (SPA) и API, они должны иметь один и тот же домен верхнего уровня. Однако они могут находиться на разных поддоменах. Кроме того, убедитесь, что вы отправляете заголовок
Accept: application/json
и либо заголовокReferer
, либо заголовокOrigin
в вашем запросе.
Конфигурирование SPA
Настройка собственных доменов
Во-первых, вы должны настроить, из каких доменов ваш SPA будет делать запросы. Вы можете указать эти домены, используя параметр stateful
в конфигурационном файле sanctum
. Этот параметр конфигурации определяет, какие домены будут поддерживать аутентификацию с «фиксацией» на основе файлов cookie сессии Laravel при выполнении запросов к вашему API.
Если вы обращаетесь к своему приложению через URL-адрес, содержащий порт (например,
127.0.0.1:8000
), то вы должны убедиться, что указали номер порта вместе с доменом.
Посредник Sanctum
Затем вы должны добавить посредник Sanctum в группу api
в файле app/Http/Kernel.php
. Этот посредник отвечает за возможность аутентификации входящих запросов от вашего SPA с использованием файлов cookie сессии Laravel, при этом позволяя запросам от сторонних или мобильных приложений аутентифицироваться с использованием токенов API:
'api' => [
\Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
\Illuminate\Routing\Middleware\ThrottleRequests::class.':api',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
CORS и Cookies
Если у вас возникли проблемы с аутентификацией вашего SPA, который выполняется на отдельном поддомене, вы, вероятно, неправильно сконфигурировали параметры CORS (совместное использование ресурсов между разными источниками) или cookie сессий.
Вы должны убедиться, что конфигурация CORS вашего приложения возвращает заголовок Access-Control-Allow-Credentials
со значением True
. Этого можно добиться, установив для параметра supports_credentials
значение true
в конфигурационном файле config/cors.php
вашего приложения.
Кроме того, вы должны включить опции withCredentials
и withXSRFToken
в глобальном экземпляре axios
вашего приложения. Обычно это делается в файле resources/js/bootstrap.js
. Если вы не используете Axios для выполнения HTTP-запросов из вашего фронтенда, вы должны выполнить аналогичную настройку для вашего собственного HTTP-клиента:
axios.defaults.withCredentials = true;
axios.defaults.withXSRFToken = true;
Наконец, вы должны убедиться, что конфигурация домена cookie сессии вашего приложения поддерживает любой поддомен вашего корневого домена. Вы можете сделать это, добавив к домену префикс .
в конфигурационном файле config/session.php
вашего приложения:
'domain' => '.domain.com',
Выполнение аутентификации SPA
Защита от CSRF
Для аутентификации вашего SPA страница «входа» вашего SPA должна сначала сделать запрос к /sanctum/csrf-cookie
для инициализации защиты от CSRF для приложения:
axios.get('/sanctum/csrf-cookie').then(response => {
// Login...
});
Во время этого запроса Laravel установит cookie XSRF-TOKEN
, содержащий текущий токен CSRF. Этот токен следует передавать в заголовке X-XSRF-TOKEN
при последующих запросах, что некоторые клиентские библиотеки HTTP, такие, как Axios и Angular HttpClient, будут делать автоматически за вас. Если ваша HTTP-библиотека JavaScript не задает автоматически значение, то вам нужно будет вручную установить заголовок X-XSRF-TOKEN
, чтобы он соответствовал значению XSRF-TOKEN
cookie, установленному этим маршрутом.
Вход в систему
После того как защита от CSRF была инициализирована, вы должны сделать POST-запрос к маршруту /login
вашего приложения Laravel. Этот маршрут /login
может быть реализован вручную или с использованием пакета безголовой аутентификации, такого как Laravel Fortify.
Если запрос на вход будет успешным, то пользователь будет аутентифицирован, и последующие запросы к маршрутам вашего приложения будут автоматически аутентифицироваться через cookie сессии, которые приложение Laravel отправило клиентской стороне. Кроме того, поскольку ваше приложение уже сделало запрос к маршруту /sanctum/csrf-cookie
, то последующие запросы должны автоматически получать защиту от CSRF, пока ваш HTTP-клиент JavaScript отправляет значение XSRF-TOKEN
cookie в заголовке X-XSRF-TOKEN
.
Конечно, если сессия вашего пользователя истекает из-за отсутствия активности, то последующие запросы к приложению Laravel могут получить ответ об ошибках 401
или 419
HTTP. В этом случае вы должны перенаправить пользователя на страницу входа в SPA.
Вы можете написать свою реализацию
/login
; однако, вы должны убедиться, что она аутентифицирует пользователя, используя стандартные службы аутентификации на основе сессии, которые предлагает Laravel. Обычно это означает использование охранника аутентификацииweb
.
Защита маршрутов SPA
Чтобы защитить маршруты так, чтобы все входящие запросы аутентифицировались, вы должны назначить охранника аутентификации sanctum
к вашим маршрутам API в вашем файле routes/api.php
. Этот охранник гарантирует, что входящие запросы аутентифицируются либо как запросы с «фиксацией» на основе файлов cookie сессии, либо содержат действительный заголовок токена 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 были успешными, вам нужно будет предоставить определение authorizer
Pusher при инициализации 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.
Выдача токенов API мобильного приложения
Для начала создайте маршрут, который принимает электронную почту / имя пользователя, пароль и имя устройства, а затем обменивает эти учетные данные на новый токен Sanctum. «Имя устройства», присвоенное этой конечной точке, предназначено для информационных целей и может иметь любое желаемое значение. В общем, значение имени устройства должно быть именем, которое узнает пользователь, например «iPhone 12 Nuno».
Как правило, вы делаете запрос к конечной точке токена с экрана «входа в систему» вашего мобильного приложения. Конечная точка вернет токен 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
-токен.
При выдаче токенов для мобильного приложения вы также можете указать полномочия токена.
Защита маршрутов API мобильного приложения
Как ранее было задокументировано, вы можете защитить маршруты так, чтобы все входящие запросы аутентифицировались, назначив маршрутам охранника аутентификации sanctum
:
Route::middleware('auth:sanctum')->get('/user', function (Request $request) {
return $request->user();
});
Отзыв токенов API мобильного приложения
Чтобы пользователи могли отзывать токены 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(),
['*']
);