При разработке приложения, когда речь идет о доступе к нему через веб-интерфейс, другими словами, при помощи веб-браузера, часто для аутентификации используется логин/пароль, а для хранения аутентифицированного состояния пользователя используется механизм сессий, который заключается в хранении уникального ключа в Cookies браузера. По этому ключу на стороне сервера можно достать сессионные данные и таким образом восстановить состояние текущего пользователя при переходе между страницами.
Я думаю, про сессию и хранение аутентификации в сессии все, даже начинающие разработчики более-менее понимают. А вот когда мы создаем точку доступа API своего приложения, то здесь аутентификация происходит немного иначе.
Так как API разрабатываются без сохранения состояния, то о сессии и сессионном хранилище говорить не приходится. А это значит, что вместо всем известного идентификатора PHPSESSID или других аналогичных, при каждом запросе нам нужно передавать что-то другое.
Какие способы аутентификации запросов к API могут быть
Логин и пароль
Можно, но так никто не делает. Зачем перекидывать каждый раз логин и пароль? Честно говоря, сам не думал глубоко над этим. Но, если посмотреть на то, как устроены API общеизвестных сервисов, то можно заметить, что чаще всего логин и пароль дает доступ ко всем функциям и данным личного кабинета, а нам зачастую нужен доступ только к нескольким отдельным функциям. Помимо прочего, вероятность компрометации логина и пароля, если мы их будем передавать при каждом запросе в открытом виде, очевидно, повышается.
Поэтому, повторюсь, логин и пароль в качестве способа аутентификации использовать можно, но это далеко не самый идеальный способ.
Одноразовый пароль
Это то самое, что просит от вас гугл, яндекс, вконтакте и прочие небезызвестные сервисы, когда вы включаете двухфакторную авторизацию.
Мы могли бы использовать одноразовый пароль при каждом запросе, но это сильно усложняет реализацию как на клиентской стороне, так и на серверной, так как требует интеграции с сервисом генерации и проверки одноразовых паролей. Но стоит отметить, что уровень надежности будет существенно выше, так как с каждым новым запросом мы будем передавать новый пароль и его случайная компрометация не будет нести какую-либо существенную угрозу для нашего API. Однако, такой способ аутентификации запросов к API вы вряд ли где-то встретите.
Аутентификация по сертификату
Если вкратце, то мы аутентифицируем пользователя по его сертификату, выданного удостоверяющим центром. При каждом запросе пользователь отправляет зашифрованную приватным ключом информацию о себе (свой сертификат) и публичный ключ, а на сервере мы расшифровываем информацию публичным ключом и убеждаемся, что доступ пытается получить доверенный пользователь. Другими словами, мы проверяем не столько какую-либо секретную фразу, а сравниваем необходимую информацию из расшифрованного сертификата (например, номер паспорта) с некоторой внутренней базой пользователей, которым мы разрешаем доступ. Сложность реализации такого способа аутентификации заключается в проверке на стороне сервера подлинности сертификата. Тема зачастую довольно сложная даже для опытных разработчиков, что уж говорить о начинающих.
Токен или API-ключ
Ну и наконец, самый доступный и распространенный способ аутентификации — по токену или api-ключу, который пользователь может получить одним из следующих способов:
- В личном кабинете пользователь сгенерировал его себе сам и теперь при каждом запросе передает этот токен, мы узнаем пользователя и даем ему нужные данные. Подходит для сервисов, предполагающих частую необходимость пользователей в обращении к API.
- Мы создали токен вручную и выдали ему по другим каналам (например, отправили в личные сообщения в телеграм) и теперь при каждом запросе он делает то же самое, что и в пункте 1. Подойдет для частных сервисов, где доступ к API выдается сильно ограниченному кругу лиц и не требует частого создания новых API-ключей.
Практическая часть
Как выглядит проверка ключа на стороне сервера. На примере фреймворка Laravel.
Создаем Middleware для защиты маршрутов API
Создаем файл app/Http/Middleware/AuthenticateApi.php
Это можно сделать как вручную, так и при помощи команды:
php artisan make:middeware AuthenticateApi
Кладем в него следующее содержимое
<?php
namespace App\Http\Middleware;
use Illuminate\Auth\Middleware\Authenticate as Middleware;
class AuthenticateApi extends Middleware
{
protected function authenticate($request, array $guards)
{
//Даем пользователю возможность передать токен (api-ключ) разными способами
//1. в адресе запроса
$token = $request->query('api_token');
if(empty($token)){
//2. Через url-form-encoded поля POST запроса
$token = $request->input('api_token');
}
if(empty($token)){
//3. Через заголовок Authorization: Bearer ......
$token = $request->bearerToken();
}
//Сравниваем токен с тем, что хранится в наших настройках. Здесь можно заменить логику на свою. Например сделать поиск токена в базе
if($token === config('apitokens')[0]) return;
//В случае неуспеха, вызываем метод сообщающий о статусе "Неавторизован"
$this->unauthenticated($request, $guards);
}
}
Регистрируем middleware
В файле app/Http/Kernel.php вносим следующие изменения
...
protected $routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class,
'auth_api' => AuthenticateApi::class, //<----регистрируем middleware
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
...
Используем для защиты маршрута
Пример использования middleware для защиты маршрута api/user/{id} от свободного доступа.
В файле routes/api.php
...
Route::middleware('auth_api')->get('/user/{id}', function(Request $request, $id){
$user = \App\Models\User::find($id);
if(!$user) return response('', 404);
return $user;
});
...
Удачи в веб-разработке! Если хочешь получать больше полезных материалов по Laravel, подписывайся на мой канал в Youtube: Lectoria. Обучение веб-разработке
Вы должны авторизоваться, чтобы оставлять комментарии.