1. Пакеты
  2. Laravel Passport

Присоединяйся к нашему Telegram сообществу @webblend!

Здесь ты найдешь сниппеты по Laravel и полезные советы по веб-разработке.

Введение

Laravel Passport предоставляет полную реализацию сервера OAuth2 для вашего приложения Laravel всего за несколько минут. Passport построен на основе League OAuth2 server, поддерживаемого Энди Миллингтоном и Саймоном Хэмпом.

Внимание Эта документация предполагает, что вы уже знакомы с OAuth2. Если вы ничего не знаете об OAuth2, рекомендуется ознакомиться с общими терминами и особенностями OAuth2 перед продолжением.

Passport или Sanctum?

Прежде чем начать, вы можете решить, не будет ли ваше приложение лучше обслужено Laravel Passport или Laravel Sanctum. Если ваше приложение абсолютно нуждается в поддержке OAuth2, то вы должны использовать Laravel Passport.

Однако, если вы пытаетесь аутентифицировать одностраничное приложение, мобильное приложение или выдавать токены API, вы должны использовать Laravel Sanctum. Laravel Sanctum не поддерживает OAuth2; однако он предоставляет гораздо более простой опыт разработки аутентификации API.

Установка

Для начала установите Passport через менеджер пакетов Composer:

composer require laravel/passport

Сервис-провайдер Passport регистрирует свой собственный каталог миграций базы данных, поэтому вы должны выполнить миграцию базы данных после установки пакета. Миграции Passport создадут таблицы, необходимые для хранения клиентов OAuth2 и токенов доступа вашего приложения:

php artisan migrate

Затем выполните команду Artisan passport:install. Эта команда создаст ключи шифрования, необходимые для генерации безопасных токенов доступа. Кроме того, команда создаст клиенты "личного доступа" и "гранта пароля", которые будут использоваться для генерации токенов доступа:

php artisan passport:install

Примечание Если вы хотите использовать UUID в качестве значения первичного ключа модели Passport Client вместо автоинкрементных целых чисел, установите Passport, используя опцию uuids.

После выполнения команды passport:install добавьте трейт Laravel\Passport\HasApiTokens в модель пользователя App\Models\User. Этот трейт предоставит несколько вспомогательных методов вашей модели, которые позволяют вам проверять токен и области видимости аутентифицированного пользователя. Если ваша модель уже использует трейт Laravel\Sanctum\HasApiTokens, вы можете удалить этот трейт:

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

Наконец, в файле конфигурации config/auth.php вашего приложения вы должны определить аутентификационный страж api и установить опцию driver в passport. Это указывает вашему приложению использовать страж TokenGuard Passport при аутентификации входящих запросов API:

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

Идентификаторы клиентов

Вы также можете выполнить команду passport:install с опцией --uuids. Эта опция указывает Passport использовать UUID вместо автоинкрементных целых чисел в качестве первичных ключей значений модели Passport Client. После выполнения команды passport:install с опцией --uuids, вам будут предоставлены дополнительные инструкции по отключению миграций Passport по умолчанию:

php artisan passport:install --uuids

Развертывание Passport

При развертывании Passport на сервера вашего приложения в первый раз вам, вероятно, нужно будет выполнить команду passport:keys. Эта команда генерирует ключи шифрования, которые Passport нужны для создания токенов доступа. Сгенерированные ключи обычно не хранятся в системе контроля версий:

php artisan passport:keys

При необходимости вы можете определить путь, откуда должны быть загружены ключи Passport. Для этого вы можете использовать метод Passport::loadKeysFrom. Обычно этот метод следует вызывать из метода boot класса App\Providers\AuthServiceProvider вашего приложения:

/**
* Зарегистрируйте любые службы аутентификации / авторизации.
*/
public function boot(): void
{
Passport::loadKeysFrom(__DIR__.'/../secrets/oauth');
}

Загрузка ключей из окружения

В качестве альтернативы вы можете опубликовать файл конфигурации Passport с помощью команды Artisan vendor:publish:

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-----"

Настройка миграции

Если вы не собираетесь использовать миграции Passport по умолчанию, вы должны вызвать метод Passport::ignoreMigrations в методе register класса App\Providers\AppServiceProvider вашего приложения. Вы можете экспортировать миграции по умолчанию с помощью команды Artisan vendor:publish:

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

Обновление Passport

При обновлении до новой основной версии Passport важно тщательно просмотреть руководство по обновлению.

Настройка

Хеширование секрета клиента

Если вы хотите, чтобы секреты вашего клиента были захешированы при их хранении в вашей базе данных, вы должны вызвать метод Passport::hashClientSecrets в методе boot класса App\Providers\AuthServiceProvider вашего приложения:

use Laravel\Passport\Passport;
 
Passport::hashClientSecrets();

После включения все секреты вашего клиента будут отображаться только для пользователя сразу после их создания. Поскольку значение секрета клиента в виде обычного текста никогда не хранится в базе данных, невозможно восстановить значение секрета, если оно потеряно.

Сроки действия токенов

По умолчанию Passport выдает токены доступа с долгим сроком действия, истекающими через год. Если вы хотите настроить более длинный/короткий срок действия токена, вы можете использовать методы tokensExpireIn, refreshTokensExpireIn и personalAccessTokensExpireIn. Эти методы следует вызывать из метода boot класса App\Providers\AuthServiceProvider вашего приложения:

/**
* Зарегистрируйте любые службы аутентификации / авторизации.
*/
public function boot(): void
{
Passport::tokensExpireIn(now()->addDays(15));
Passport::refreshTokensExpireIn(now()->addDays(30));
Passport::personalAccessTokensExpireIn(now()->addMonths(6));
}

Внимание Столбцы expires_at в таблицах базы данных Passport доступны только для чтения и предназначены только для отображения. При выдаче токенов Passport хранит информацию об их сроке действия в подписанных и зашифрованных токенах. Если вам нужно аннулировать токен, вы должны отозвать его.

Переопределение моделей по умолчанию

Вы можете свободно расширять используемые внутренне Passport модели, определив свою собственную модель и расширив соответствующую модель Passport:

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

После определения вашей модели вы можете указать Passport использовать вашу собственную модель с помощью класса Laravel\Passport\Passport. Обычно вы должны сообщить Passport о ваших собственных моделях в методе boot класса App\Providers\AuthServiceProvider вашего приложения:

use App\Models\Passport\AuthCode;
use App\Models\Passport\Client;
use App\Models\Passport\PersonalAccessClient;
use App\Models\Passport\RefreshToken;
use App\Models\Passport\Token;
 
/**
* Зарегистрируйте любые службы аутентификации / авторизации.
*/
public function boot(): void
{
Passport::useTokenModel(Token::class);
Passport::useRefreshTokenModel(RefreshToken::class);
Passport::useAuthCodeModel(AuthCode::class);
Passport::useClientModel(Client::class);
Passport::usePersonalAccessClientModel(PersonalAccessClient::class);
}

Переопределение маршрутов

Иногда вам может потребоваться настроить маршруты, определенные Passport. Для достижения этого сначала вам нужно проигнорировать маршруты, зарегистрированные Passport, добавив Passport::ignoreRoutes в метод register класса AppServiceProvider вашего приложения:

use Laravel\Passport\Passport;
 
/**
* Зарегистрируйте любые службы приложения.
*/
public function register(): void
{
Passport::ignoreRoutes();
}

Затем вы можете скопировать маршруты, определенные Passport в его файле маршрутов в файл routes/web.php вашего приложения и изменить их по своему усмотрению:

Route::group([
'as' => 'passport.',
'prefix' => config('passport.path', 'oauth'),
'namespace' => '\Laravel\Passport\Http\Controllers',
], function () {
// Маршруты Passport...
});

Выдача токенов доступа

Использование OAuth2 через коды авторизации - это то, с чем большинство разработчиков знакомы в OAuth2. При использовании кодов авторизации приложение-клиент перенаправляет пользователя на ваш сервер, где они будут либо утверждены, либо отклонены в запросе на выдачу токена доступа клиенту.

Управление клиентами

Сначала разработчики, создающие приложения, которым необходимо взаимодействовать с вашим API, должны зарегистрировать свое приложение, создав "клиента". Обычно это включает предоставление имени своего приложения и URL, на который ваше приложение может перенаправить после утверждения пользователем их запроса на авторизацию.

Команда passport:client

Самый простой способ создать клиента - использовать команду Artisan passport:client. Эта команда может использоваться для создания ваших собственных клиентов для тестирования вашей функциональности OAuth2. При выполнении команды client Passport запросит у вас дополнительную информацию о вашем клиенте и предоставит вам идентификатор и секрет клиента:

php artisan passport:client

Redirect URLs

Если вы хотите разрешить несколько URL-адресов перенаправления для вашего клиента, вы можете указать их, используя разделенный запятыми список при запросе URL-адреса командой passport:client. Любые URL-адреса, содержащие запятые, должны быть закодированы в URL:

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

JSON API

Поскольку пользователи вашего приложения не смогут использовать команду client, Passport предоставляет JSON API, которое вы можете использовать для создания клиентов. Это позволяет вам избежать необходимости вручную создавать контроллеры для создания, обновления и удаления клиентов.

Тем не менее, вам нужно будет сопоставить JSON API Passport с вашим собственным интерфейсом, чтобы предоставить панель управления вашим пользователям для управления своими клиентами. Далее мы рассмотрим все конечные точки API для управления клиентами. Для удобства мы будем использовать Axios для демонстрации выполнения HTTP-запросов к конечным точкам.

JSON API защищен промежуточным ПО web и auth; следовательно, к нему можно обращаться только из вашего собственного приложения. Из внешнего источника он не может быть вызван.

GET /oauth/clients

Этот маршрут возвращает все клиенты для аутентифицированного пользователя. Это в основном полезно для отображения всех клиентов пользователя, чтобы они могли их редактировать или удалять:

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

POST /oauth/clients

Этот маршрут используется для создания новых клиентов. Для этого требуется два фрагмента данных: name клиента и URL-адрес redirect. 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 => {
// Список ошибок в ответе...
});

PUT /oauth/clients/{client-id}

Этот маршрут используется для обновления клиентов. Для этого требуется два фрагмента данных: name клиента и URL-адрес redirect. 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 => {
// Список ошибок в ответе...
});

DELETE /oauth/clients/{client-id}

Этот маршрут используется для удаления клиентов:

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

Запрос токенов

Перенаправление для авторизации

После создания клиента разработчики могут использовать их идентификатор и секрет клиента для запроса кода авторизации и токена доступа от вашего приложения. Сначала прикладное приложение должно сделать перенаправление на ваш маршрут /oauth/authorize следующим образом:

use Illuminate\Http\Request;
use Illuminate\Support\Str;
 
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://third-party-app.com/callback',
'response_type' => 'code',
'scope' => '',
'state' => $state,
// 'prompt' => '', // "none", "consent", or "login"
]);
 
return redirect('http://passport-app.test/oauth/authorize?'.$query);
});

Параметр prompt может использоваться для указания поведения аутентификации приложения Passport.

Если значение prompt равно none, Passport всегда будет выдавать ошибку аутентификации, если пользователь не аутентифицирован в приложении Passport. Если значение равно consent, Passport всегда будет отображать экран подтверждения авторизации, даже если все разрешения были предварительно предоставлены потребляющему приложению. Когда значение равно login, приложение Passport всегда будет предлагать пользователю повторно войти в приложение, даже если у них уже есть существующая сессия.

Если значение prompt не предоставлено, пользователю будет предложено подтвердить авторизацию только в том случае, если он ранее не предоставил доступ приложению-потребителю для запрошенных разрешений.

Примечание Помните, что маршрут /oauth/authorize уже определен Passport. Вам не нужно вручную определять этот маршрут.

Утверждение запроса

При получении запросов на авторизацию Passport автоматически отвечает в зависимости от значения параметра prompt (если он присутствует) и может отображать шаблон пользователю, позволяя ему подтвердить или отклонить запрос на авторизацию. Если они утверждают запрос, их перенаправит обратно на redirect_uri, указанный потребляющим приложением. redirect_uri должен совпадать с redirect URL, указанным при создании клиента.

Если вы хотите настроить экран подтверждения авторизации, вы можете опубликовать представления Passport с помощью команды Artisan vendor:publish. Опубликованные представления будут помещены в каталог resources/views/vendor/passport:

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

Иногда вам может потребоваться пропустить запрос на авторизацию, например, при авторизации клиента первой стороны. Вы можете сделать это, расширив модель Client и определив метод skipsAuthorization. Если skipsAuthorization возвращает true, клиент будет утвержден, и пользователь будет немедленно перенаправлен обратно на redirect_uri, за исключением случая, когда потребляющее приложение явно установило параметр prompt при перенаправлении для авторизации:

<?php
 
namespace App\Models\Passport;
 
use Laravel\Passport\Client as BaseClient;
 
class Client extends BaseClient
{
/**
* Определить, следует ли клиенту пропустить запрос авторизации.
*/
public function skipsAuthorization(): bool
{
return $this->firstParty();
}
}

Преобразование кодов авторизации в токены доступа

Если пользователь утверждает запрос на авторизацию, его перенаправляет обратно в потребляющее приложение. Сначала потребитель должен проверить параметр state по значению, которое было сохранено до перенаправления. Если параметр state совпадает, потребитель должен выполнить запрос POST к вашему приложению для запроса токена доступа. В запросе должен быть включен код авторизации, который был выдан вашим приложением, когда пользователь утвердил запрос на авторизацию:

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;
 
Route::get('/callback', function (Request $request) {
$state = $request->session()->pull('state');
 
throw_unless(
strlen($state) > 0 && $state === $request->state,
InvalidArgumentException::class,
'Invalid state value.'
);
 
$response = Http::asForm()->post('http://passport-app.test/oauth/token', [
'grant_type' => 'authorization_code',
'client_id' => 'client-id',
'client_secret' => 'client-secret',
'redirect_uri' => 'http://third-party-app.com/callback',
'code' => $request->code,
]);
 
return $response->json();
});

Этот маршрут /oauth/token вернет JSON-ответ с атрибутами access_token, refresh_token и expires_in. Атрибут expires_in содержит количество секунд до истечения срока действия токена доступа.

Примечание Как и маршрут /oauth/authorize, маршрут /oauth/token уже определен для вас Passport. Нет необходимости вручную определять этот маршрут.

JSON API

Passport также включает JSON API для управления авторизованными токенами доступа. Вы можете сопоставить его с собственным интерфейсом для предоставления пользователям панели управления токенами доступа. Для удобства мы будем использовать Axios для демонстрации выполнения HTTP-запросов к конечным точкам. JSON API защищен промежуточным ПО web и auth; следовательно, к нему можно обращаться только из вашего собственного приложения.

GET /oauth/tokens

Этот маршрут возвращает все авторизованные токены доступа, которые аутентифицированный пользователь создал. Это в основном полезно для отображения всех токенов пользователя, чтобы они могли их отменить:

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

DELETE /oauth/tokens/{token-id}

Этот маршрут может использоваться для отзыва авторизованных токенов доступа и связанных с ними токенов обновления:

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

Обновление токенов

Если ваше приложение выдает токены доступа с коротким сроком действия, пользователям нужно будет обновлять их с помощью токена обновления, предоставленного им при выдаче токена доступа:

use Illuminate\Support\Facades\Http;
 
$response = Http::asForm()->post('http://passport-app.test/oauth/token', [
'grant_type' => 'refresh_token',
'refresh_token' => 'the-refresh-token',
'client_id' => 'client-id',
'client_secret' => 'client-secret',
'scope' => '',
]);
 
return $response->json();

Этот маршрут /oauth/token вернет JSON-ответ с атрибутами access_token, refresh_token и expires_in. Атрибут expires_in содержит количество секунд до истечения срока действия токена доступа.

Аннулирование токенов

Вы можете отозвать токен, используя метод revokeAccessToken в Laravel\Passport\TokenRepository. Вы можете отозвать токены обновления токена с использованием метода revokeRefreshTokensByAccessTokenId в Laravel\Passport\RefreshTokenRepository. Эти классы можно разрешить с использованием контейнера служб Laravel:

use Laravel\Passport\TokenRepository;
use Laravel\Passport\RefreshTokenRepository;
 
$tokenRepository = app(TokenRepository::class);
$refreshTokenRepository = app(RefreshTokenRepository::class);
 
// Аннулировать токен доступа...
$tokenRepository->revokeAccessToken($tokenId);
 
// Аннулировать все токены обновления токена...
$refreshTokenRepository->revokeRefreshTokensByAccessTokenId($tokenId);

Очистка токенов

Когда токены были отозваны или истекли, вы можете захотеть удалить их из базы данных. Команда Artisan passport:purge Passport может сделать это за вас:

# Purge revoked and expired tokens and auth codes...
php artisan passport:purge
 
# Only purge tokens expired for more than 6 hours...
php artisan passport:purge --hours=6
 
# Only purge revoked tokens and auth codes...
php artisan passport:purge --revoked
 
# Only purge expired tokens and auth codes...
php artisan passport:purge --expired

Вы также можете настроить запланированную задачу в классе App\Console\Kernel вашего приложения для автоматической очистки токенов по расписанию:

/**
* Определить расписание команд приложения.
*/
protected function schedule(Schedule $schedule): void
{
$schedule->command('passport:purge')->hourly();
}

Авторизация кода с PKCE

Подтверждение кода с предоставлением "Проверочного ключа для обмена кода" (PKCE) - это безопасный способ аутентификации одностраничных приложений или нативных приложений для доступа к вашему API. Этот грант следует использовать, когда нельзя гарантировать, что секрет клиента будет храниться конфиденциально, или чтобы уменьшить угрозу перехвата кода авторизации злоумышленником. Комбинация "проверочного кода" и "запроса кода" заменяет секрет клиента при обмене кодом авторизации на токен доступа.

Создание клиента

Прежде чем ваше приложение сможет выдавать токены с использованием гранта авторизации с PKCE, вам нужно создать клиент с поддержкой PKCE. Вы можете сделать это, используя команду Artisan 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 вашего приложения:

use Illuminate\Http\Request;
use Illuminate\Support\Str;
 
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://third-party-app.com/callback',
'response_type' => 'code',
'scope' => '',
'state' => $state,
'code_challenge' => $codeChallenge,
'code_challenge_method' => 'S256',
// 'prompt' => '', // "none", "consent", or "login"
]);
 
return redirect('http://passport-app.test/oauth/authorize?'.$query);
});

Преобразование кодов авторизации в токены доступа

Если пользователь утверждает запрос на авторизацию, его перенаправляет обратно в потребляющее приложение. Потребитель должен проверить параметр state по значению, которое было сохранено до перенаправления, как в стандартном гранте авторизации с кодом.

Если параметр state совпадает, потребитель должен выполнить запрос POST к вашему приложению для запроса токена доступа. В запросе должен быть включен код авторизации, который был выдан вашим приложением, когда пользователь утвердил запрос на авторизацию, а также изначально сгенерированный проверочный код:

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;
 
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 = Http::asForm()->post('http://passport-app.test/oauth/token', [
'grant_type' => 'authorization_code',
'client_id' => 'client-id',
'redirect_uri' => 'http://third-party-app.com/callback',
'code_verifier' => $codeVerifier,
'code' => $request->code,
]);
 
return $response->json();
});

Токены гранта пароля

Внимание Мы больше не рекомендуем использовать токены гранта пароля. Вместо этого вы должны выбрать тип гранта, который в настоящее время рекомендуется OAuth2 Server.

Грант пароля OAuth2 позволяет вашим другим приложениям первой стороны, таким как мобильное приложение, получать токен доступа, используя адрес электронной почты/имя пользователя и пароль. Это позволяет вам безопасно выдавать токены доступа вашим приложениям первой стороны, не требуя от пользователей проходить полный поток перенаправления кода авторизации OAuth2.

Создание клиента для гранта пароля

Прежде чем ваше приложение сможет выдавать токены с использованием гранта пароля, вам нужно создать клиент гранта пароля. Вы можете сделать это, используя команду Artisan passport:client с опцией --password. Если вы уже выполнили команду passport:install, вам не нужно выполнять эту команду:

php artisan passport:client --password

Запрос токенов

После создания клиента гранта пароля вы можете запросить токен доступа, выполнив запрос POST к маршруту /oauth/token с адресом электронной почты пользователя и паролем. Помните, что этот маршрут уже зарегистрирован Passport, поэтому нет необходимости определять его вручную. Если запрос успешен, вы получите access_token и refresh_token в JSON-ответе от сервера:

use Illuminate\Support\Facades\Http;
 
$response = Http::asForm()->post('http://passport-app.test/oauth/token', [
'grant_type' => 'password',
'client_id' => 'client-id',
'client_secret' => 'client-secret',
'username' => '[email protected]',
'password' => 'my-password',
'scope' => '',
]);
 
return $response->json();

Примечание Помните, что токены доступа долговечны по умолчанию. Однако вы свободны настроить максимальный срок действия токена доступа, если это необходимо.

Запрос всех областей

При использовании гранта пароля или гранта учетных данных клиента вы можете разрешить токен для всех разрешений, поддерживаемых вашим приложением. Для этого запросите разрешение *. Если вы запросите разрешение *, метод can на экземпляре токена всегда вернет true. Это разрешение может быть предоставлено только токену, выданному с использованием гранта password или client_credentials:

use Illuminate\Support\Facades\Http;
 
$response = Http::asForm()->post('http://passport-app.test/oauth/token', [
'grant_type' => 'password',
'client_id' => 'client-id',
'client_secret' => 'client-secret',
'username' => '[email protected]',
'password' => 'my-password',
'scope' => '*',
]);

Настройка поставщика пользователя

Если ваше приложение использует более одного поставщика аутентификации пользователя, вы можете указать, какой поставщик пользователей использует клиент гранта пароля, предоставив опцию --provider при создании клиента с помощью команды artisan passport:client --password. Указанное имя поставщика должно соответствовать допустимому поставщику, определенному в конфигурационном файле вашего приложения config/auth.php. Затем вы можете защитить свой маршрут, используя промежуточное ПО, чтобы удостовериться, что только пользователи из указанного поставщика могут быть авторизованы.

Настройка имени пользователя

При аутентификации с использованием гранта пароля Passport будет использовать атрибут email вашей модели аутентификации в качестве "имени пользователя". Однако вы можете настроить это поведение, определив метод findForPassport в своей модели:

<?php
 
namespace App\Models;
 
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Passport\HasApiTokens;
 
class User extends Authenticatable
{
use HasApiTokens, Notifiable;
 
/**
* Найти экземпляр пользователя для заданного имени пользователя.
*/
public function findForPassport(string $username): User
{
return $this->where('username', $username)->first();
}
}

Настройка проверки пароля

При аутентификации с использованием гранта пароля Passport будет использовать атрибут password вашей модели для проверки предоставленного пароля. Если у вашей модели нет атрибута password или вы хотите настроить логику проверки пароля, вы можете определить метод validateForPassportPasswordGrant в своей модели:

<?php
 
namespace App\Models;
 
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;
 
/**
* Проверить пароль пользователя для предоставления Passport права на предоставление пароля.
*/
public function validateForPassportPasswordGrant(string $password): bool
{
return Hash::check($password, $this->password);
}
}

Токены гранта на основе указания

Внимание Мы больше не рекомендуем использовать токены неявного гранта. Вместо этого вы должны выбрать тип гранта, который в настоящее время рекомендуется OAuth2 Server.

Неявный грант похож на грант кода авторизации; однако токен возвращается клиенту без обмена кодом авторизации. Этот грант наиболее часто используется для JavaScript- или мобильных приложений, где учетные данные клиента не могут быть безопасно сохранены. Чтобы включить грант, вызовите метод enableImplicitGrant в методе boot класса App\Providers\AuthServiceProvider вашего приложения:

/**
* Зарегистрируйте любые службы аутентификации / авторизации.
*/
public function boot(): void
{
Passport::enableImplicitGrant();
}

После включения гранта разработчики могут использовать идентификатор своего клиента для запроса токена доступа из вашего приложения. Потребляющее приложение должно сделать перенаправление на маршрут /oauth/authorize вашего приложения, например:

use Illuminate\Http\Request;
 
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://third-party-app.com/callback',
'response_type' => 'token',
'scope' => '',
'state' => $state,
// 'prompt' => '', // "none", "consent", or "login"
]);
 
return redirect('http://passport-app.test/oauth/authorize?'.$query);
});

Примечание Помните, что маршрут /oauth/authorize уже определен Passport. Вам не нужно вручную определять этот маршрут.

Токены гранта учетных данных клиента

Грант учетных данных клиента подходит для аутентификации между машинами. Например, вы можете использовать этот грант в запланированной задаче, выполняющей обслуживание через API.

Прежде чем ваше приложение сможет выдавать токены с использованием гранта учетных данных клиента, вам нужно создать клиент гранта учетных данных клиента. Вы можете сделать это, используя опцию --client команды Artisan passport:client:

php artisan passport:client --client

Затем, чтобы использовать этот тип гранта, вы можете добавить промежуточное ПО CheckClientCredentials в свойство $middlewareAliases файла вашего приложения app/Http/Kernel.php:

use Laravel\Passport\Http\Middleware\CheckClientCredentials;
 
protected $middlewareAliases = [
'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:

use Illuminate\Support\Facades\Http;
 
$response = Http::asForm()->post('http://passport-app.test/oauth/token', [
'grant_type' => 'client_credentials',
'client_id' => 'client-id',
'client_secret' => 'client-secret',
'scope' => 'your-scope',
]);
 
return $response->json()['access_token'];

Персональные токены доступа

Иногда ваши пользователи могут захотеть выдавать себе токены без прохождения типичного потока перенаправления кода авторизации. Разрешение пользователям выдавать себе токены через пользовательский интерфейс вашего приложения может быть полезным для того, чтобы пользователи могли экспериментировать с вашим API или в качестве более простого способа выдачи токенов доступа в целом.

Примечание Если ваше приложение в основном использует Passport для выдачи персональных токенов доступа, рассмотрите возможность использования Laravel Sanctum, легковесной библиотеки Laravel для выдачи токенов доступа к API.

Создание клиента для персональных токенов доступа

Прежде чем ваше приложение сможет выдавать персональные токены доступа, вам нужно создать клиент персонального доступа. Вы можете сделать это, выполнив команду Artisan passport:client с опцией --personal. Если вы уже выполнили команду passport:install, вам не нужно выполнять эту команду:

php artisan passport:client --personal

После создания вашего клиента для персонального доступа поместите идентификатор клиента и значение секрета в открытом виде в файл .env вашего приложения:

PASSPORT_PERSONAL_ACCESS_CLIENT_ID="client-id-value"
PASSPORT_PERSONAL_ACCESS_CLIENT_SECRET="unhashed-client-secret-value"

Управление персональными токенами доступа

После создания клиента для персонального доступа вы можете выдавать токены для указанного пользователя, используя метод createToken для экземпляра модели App\Models\User. Метод createToken принимает имя токена в качестве первого аргумента и необязательный массив областей видимости в качестве второго аргумента:

use App\Models\User;
 
$user = User::find(1);
 
// Создание токена без областей...
$token = $user->createToken('Token Name')->accessToken;
 
// Создание токена с областями...
$token = $user->createToken('My Token', ['place-orders'])->accessToken;

JSON API

Passport также включает JSON API для управления персональными токенами доступа. Вы можете использовать его с вашим собственным интерфейсом для предоставления пользователям панели управления персональными токенами. Ниже мы рассмотрим все конечные точки API для управления персональными токенами доступа. Для удобства мы будем использовать Axios для демонстрации выполнения HTTP-запросов к конечным точкам.

JSON API защищен промежуточным ПО web и auth; поэтому его можно вызывать только из вашего собственного приложения. Из внешнего источника это сделать нельзя.

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 => {
// Список ошибок в ответе...
});

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

Этот маршрут может использоваться для отзыва персональных токенов доступа:

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

Защита маршрутов

Через промежуточное ПО

Passport включает сторожевой механизм аутентификации, который будет проверять токены доступа во входящих запросах. После настройки сторожевого механизма api для использования драйвера passport вам нужно только указать промежуточное ПО auth:api на любых маршрутах, для которых требуется действительный токен доступа:

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

Внимание Если вы используете токены гранта учетных данных клиента, вы должны использовать промежуточное ПО клиента, чтобы защитить ваши маршруты, а не промежуточное ПО auth:api.

Несколько аутентификационных стражей

Если ваше приложение аутентифицирует разные типы пользователей, которые, возможно, используют совершенно разные модели Eloquent, вам, вероятно, придется определить конфигурацию сторожа для каждого типа поставщика пользователей в вашем приложении. Это позволяет вам защищать запросы, предназначенные для конкретных поставщиков пользователей. Например, учитывая следующую конфигурацию сторожа в файле конфигурации config/auth.php:

'api' => [
'driver' => 'passport',
'provider' => 'users',
],
 
'api-customers' => [
'driver' => 'passport',
'provider' => 'customers',
],

В следующем маршруте будет использоваться сторож api-customers, который использует поставщика пользователей customers, для аутентификации входящих запросов:

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

Примечание Для получения дополнительной информации о использовании нескольких поставщиков пользователей с Passport обратитесь к документации по гранту паролей.

Передача токена доступа

При вызове маршрутов, защищенных Passport, потребителям вашего API следует указывать свой токен доступа как токен Bearer в заголовке Authorization своего запроса. Например, при использовании библиотеки Guzzle HTTP:

use Illuminate\Support\Facades\Http;
 
$response = Http::withHeaders([
'Accept' => 'application/json',
'Authorization' => 'Bearer '.$accessToken,
])->get('https://passport-app.test/api/user');
 
return $response->json();

Области токенов

Области позволяют клиентам вашего API запросить определенный набор разрешений при запросе авторизации для доступа к учетной записи. Например, если вы создаете приложение электронной коммерции, не все потребители API будут нуждаться в возможности размещать заказы. Вместо этого вы можете разрешить потребителям запрашивать авторизацию только для доступа к статусам отгрузок. Другими словами, области позволяют пользователям вашего приложения ограничивать действия стороннего приложения от их имени.

Определение областей

Вы можете определить области своего API, используя метод Passport::tokensCan в методе boot класса App\Providers\AuthServiceProvider вашего приложения. Метод tokensCan принимает массив имен областей и описаний областей. Описание области может быть любым и будет отображаться пользователям на экране подтверждения авторизации:

/**
* Зарегистрируйте любые службы аутентификации / авторизации.
*/
public function boot(): void
{
Passport::tokensCan([
'place-orders' => 'Place orders',
'check-status' => 'Check order status',
]);
}

Область по умолчанию

Если клиент не запрашивает какие-либо конкретные области, вы можете настроить свой сервер Passport на прикрепление областей по умолчанию к токену с помощью метода setDefaultScope. Обычно вы должны вызывать этот метод из метода boot класса App\Providers\AuthServiceProvider вашего приложения:

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

Примечание По умолчанию области Passport не применяются к персональным токенам доступа, созданным пользователем.

Назначение областей токенам

При запросе кодов авторизации

При запросе токена доступа с использованием гранта авторизации по коду потребители должны указать свои желаемые области в параметре строки запроса 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://passport-app.test/oauth/authorize?'.$query);
});

При выдаче персональных токенов доступа

Если вы выдаете персональные токены доступа с использованием метода createToken модели App\Models\User, вы можете передать массив желаемых областей вторым аргументом методу:

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

Проверка областей

Passport включает два промежуточных программы, которые можно использовать для проверки того, что входящий запрос аутентифицирован токеном, которому предоставлена определенная область. Для начала добавьте следующие промежуточные программы в свойство $middlewareAliases файла app/Http/Kernel.php вашего приложения:

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

Проверка всех областей

Промежуточную программу scopes можно назначить маршруту для проверки того, что у токена доступа входящего запроса есть все перечисленные области:

Route::get('/orders', function () {
// Токен доступа имеет области "check-status" и "place-orders"...
})->middleware(['auth:api', 'scopes:check-status,place-orders']);

Проверка любых областей

Промежуточную программу scope можно назначить маршруту для проверки того, что у токена доступа входящего запроса есть хотя бы одна из перечисленных областей:

Route::get('/orders', function () {
// Токен доступа имеет либо область "check-status", либо "place-orders"...
})->middleware(['auth:api', 'scope:check-status,place-orders']);

Проверка областей в экземпляре токена

После входа аутентифицированного запроса с токеном доступа в ваше приложение, вы все равно можете проверить, есть ли у токена доступа определенная область, используя метод tokenCan на аутентифицированном экземпляре App\Models\User:

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

Дополнительные методы области

Метод scopeIds вернет массив всех определенных идентификаторов/имен:

use Laravel\Passport\Passport;
 
Passport::scopeIds();

Метод scopes вернет массив всех определенных областей в виде экземпляров Laravel\Passport\Scope:

Passport::scopes();

Метод scopesFor вернет массив экземпляров Laravel\Passport\Scope, соответствующих заданным идентификаторам/именам:

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

Вы можете определить, была ли задана определенная область с использованием метода hasScope:

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

Использование вашего API с помощью JavaScript

При создании API может быть чрезвычайно полезно иметь возможность потреблять свой собственный API из вашего приложения JavaScript. Этот подход к разработке API позволяет вашему собственному приложению потреблять то же самое API, которое вы предоставляете миру. Это API может использоваться вашим веб-приложением, мобильными приложениями, сторонними приложениями и любыми SDK, которые вы можете опубликовать в различных менеджерах пакетов.

Обычно, если вы хотите потреблять свой API из вашего приложения JavaScript, вам нужно вручную отправлять токен доступа в приложение и передавать его с каждым запросом к вашему приложению. Однако Passport включает промежуточное ПО, которое может обработать это за вас. Все, что вам нужно сделать, это добавить промежуточное ПО CreateFreshApiToken в вашу группу промежуточного ПО web в файле app/Http/Kernel.php:

'web' => [
// Другие промежуточные программы...
\Laravel\Passport\Http\Middleware\CreateFreshApiToken::class,
],

Внимание Убедитесь, что промежуточное ПО CreateFreshApiToken находится в конце вашего стека промежуточного ПО.

Это промежуточное ПО добавит куки laravel_token к исходящим ответам. Этот файл cookie содержит зашифрованный JWT, который Passport будет использовать для аутентификации запросов API из вашего приложения JavaScript. JWT имеет время жизни, равное значению конфигурации session.lifetime. Теперь, поскольку браузер автоматически будет отправлять куки со всеми последующими запросами, вы можете делать запросы к API вашего приложения, не явно передавая токен доступа:

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

Настройка имени файла cookie

При необходимости вы можете настроить имя куки laravel_token с помощью метода Passport::cookie. Обычно этот метод следует вызывать из метода boot класса App\Providers\AuthServiceProvider вашего приложения:

/**
* Зарегистрируйте любые службы аутентификации / авторизации.
*/
public function boot(): void
{
Passport::cookie('custom_name');
}

Защита от CSRF

При использовании этого метода аутентификации вам нужно будет удостовериться, что ваши запросы включают действительный заголовок CSRF-токена. Входящий набор Laravel JavaScript по умолчанию включает в себя экземпляр Axios, который автоматически будет использовать зашифрованное значение куки XSRF-TOKEN для отправки заголовка X-XSRF-TOKEN в запросах с тем же происхождением.

Примечание Если вы выберете отправку заголовка X-CSRF-TOKEN вместо X-XSRF-TOKEN, вам нужно использовать незашифрованный токен, предоставленный csrf_token().

События

Passport вызывает события при выдаче токенов доступа и токенов обновления. Вы можете использовать эти события для очистки или отзыва других токенов доступа в вашей базе данных. При необходимости вы можете прикрепить слушателей к этим событиям в классе App\Providers\EventServiceProvider вашего приложения:

/**
* Сопоставления обработчиков событий для приложения.
*
* @var array
*/
protected $listen = [
'Laravel\Passport\Events\AccessTokenCreated' => [
'App\Listeners\RevokeOldTokens',
],
 
'Laravel\Passport\Events\RefreshTokenCreated' => [
'App\Listeners\PruneOldTokens',
],
];

Тестирование

Метод actingAs Passport можно использовать для указания текущего аутентифицированного пользователя, а также его областей. Первый аргумент, переданный методу actingAs, - это экземпляр пользователя, а второй - массив областей, которые должны быть предоставлены токену пользователя:

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

Метод actingAsClient Passport можно использовать для указания текущего аутентифицированного клиента, а также его областей. Первый аргумент, переданный методу actingAsClient, - это экземпляр клиента, а второй - массив областей, которые должны быть предоставлены токену клиента:

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