В прошлых постах я обьяснял как создать собственный модуль и контроллеры в Битриксе. Ссылки на них в конце статьи. Сегодня напишу как создать собственную авторизацию.
Зачем вообще создавать свое, если можно воспользоваться возможностями Битрикс? В битриксе уже есть своя система авторизации. Это — Basic auth, то есть пользователю нужно будет ввести свой логин и пароль, чтобы получить доступ к ресурсу. Есть также система авторизации используемая в REST методах стандартных модулей Битрикса.
Если в первом случае нужно знать логин и пароль пользователя, то во втором нужно воспользоваться OAuth2 от Битрикса, используемый, например, в локальных приложениях. А что если хотим написать бекенд не для Битрикс клиента, если какая-то программа, пусть даже собственная десктоп система или другое веб-приложение, должна общаться с бекендом? Раскрыть ему все логины и пароли, вкручивать мертвенно несгибаемый OAuth2 от Битрикса?
Не проше ли написать свою?
При том, что написать такое не займет более десятка строк кода и нескольких минут для вас, хотя у меня ушло несколько дней, прежде чем понял, что переиспользовать Битриксовую авторизацию не получится.
Итак, суть задачи — у вас есть третье веб приложение, которое общается с модулем, созданный в прошлых статьях. У него должен быть доступ к методам и нужно как то авторизовать его. Что можно использовать? Oauth2, JWT tokens?
В начале был токен
Простой токен. Для начала. В следующей статье напишу как перейти на JWT токен, чтобы можно было понять какой пользователь обратился к REST.
Весь код находится в репозитории https://github.com/Carsak/bitrix-custom-module/tree/step3
Код будет работать на PHP >= 8.x
Что добавилось?
Появился собственный ActionFilter SimpleToken
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
final class SimpleToken extends Base { private const INVALID_TOKEN = 401; private const TOKEN = 'simple_token'; public function onBeforeAction(Event $event): ?EventResult { $request = Application::getInstance()->getContext()->getRequest(); $token = $request->getHeader('token'); \CModule::IncludeModule('almat.su'); if ($token) { if ($token !== self::TOKEN) { $this->addError(new Error('Неверный токен', self::INVALID_TOKEN)); return new EventResult(EventResult::ERROR, '', 'almat.su', $this); } else { /** @var \CUser $USER */ global $USER; // по умолчанию авторизация из-под админа $USER->Authorize(1); } } return null; } } |
Проверяет на корректность токена. Если все верно, пропускает дальше, иначе выводит ошибку о неверном токене. Токен передается в хедере запроса
1 2 3 4 |
curl --location 'http://192.168.0.11/almat/su/user/' \ --header 'token: simple_token' |
Этот код НЕ работает если не отключить стандартную авторизацию Битрикса
Зачем отключать авторизацию битрикса?
Из за порядка загрузки страницы. Битрикс запускает стандартную авторизацию до запуска контроллеров. То есть, если не передать логин и пароль, то выполнение не дойдет до контроллеров. Поэтому было добавлено в событие
1 2 3 4 5 6 7 8 9 |
\Bitrix\Main\EventManager::getInstance()->registerEventHandler( 'main', 'onPageStart', $this->MODULE_ID, '\Almat\Su\EventHandler', 'disableBitrixAuth' ); |
Отключение стандартной авторизации, ведь она делегировано классу SimpleToken.
Важно!
Обратите внимание https://github.com/Carsak/bitrix-custom-module/blob/step3/modules/almat.su/lib/eventhandler.php
Проверка, что авторизация отключиться только для этого namespace.
Замените Almat\Su\Controller на свой namespace
Кстати, в этому уроке представлен еще один метод авто загрузки классов в Битриксе. Код нужно добавить в include.php модуля
1 2 3 4 5 6 7 8 9 10 |
$classes = [ 'Almat\Su\Controller\ActionFilter\SimpleToken' => 'controller/actionfilter/SimpleToken.php', ]; \Bitrix\Main\Loader::registerAutoLoadClasses( 'almat.su', $classes, ); |
Повторюсь, весь рабочий код выложен на https://github.com/Carsak/bitrix-custom-module/tree/step3
Ссылки на предыдущие статьи по теме создания модуля:
· Permalink
Алмат, привет. Покажи пример реализации авторизации через jwt, хочу использовать для react js приложения.
· Permalink
Виктор, извините за поздний ответ. Не увидел вовремя ваш комментарий.
Если хотите получить быстрый ответ, то можете написать в телеграмм
https://t.me/almatphp
Комментарий тут оставил для индексации гуглом, может кто поделиться своим опытом, или просто похвалит автора за труды
· Permalink
Спасибо за статью! Нашел небольшую дырочку, если в заголовке не передать «token», т е вообще не указать такой заголовок, то авторизация пропустит и выполнится код, так как стандартную авторизацию мы выключили. Необходимо добавить еще одно исключение в случае, если токен вообще не прислали.
public function onBeforeAction(Event $event): ?EventResult
{
$request = Application::getInstance()->getContext()->getRequest();
$token = $request->getHeader(‘token’);
\CModule::IncludeModule(‘tdt.onec’);
if ($token) {
if ($token !== self::TOKEN) {
$this->addError(new Error(‘Неверный токен’, self::INVALID_TOKEN));
return new EventResult(EventResult::ERROR, », ‘almat.su’, $this);
} else {
/** @var \CUser $USER */
global $USER;
$USER->Authorize(1);
}
}else{
$this->addError(new Error(‘Токен не указан’, self::INVALID_TOKEN));
return new EventResult(EventResult::ERROR, », ‘almat.su’, $this);
}
return null;
}