Авторизация по номеру телефона

События

Прослушиваемые события

При установке модуля сразу регистрируются обработчики на события:

  • Главный модуль (main), событие OnBeforeProlog - используется для восстановления доступа пользователя к сайту через email. При восстановлении доступа на почту отправляется временная ссылка, при переходе по которой в этом обработчике проверяется наличие метки, валидность данный и время действия ссылки. В результате будет произведена попытка автоматически авторизовтаь пользователя.

  • Главный модуль (main), событие OnBeforeUserUpdate - используется для защиты от смены пользователем номера телефона на произвольный, не подтвержденный. Отключить защиту можно в настройках модуля.

  • Главный модуль (main), событие OnBeforeUserAdd - используется для блокировки стандартной регистраии. Используется если включена блокировка стандартной регистраии, есть параметр url - register=yes, и текущая страница не является административной страницей

  • Главный модуль (main), событие OnAfterUserAdd - проверяет наличие номера телефона в одном из полей указанных как источник автозаполнения и если найден, сохраняет в качестве телефона пользователя. Используется при включеном автозаполнении.

Cобытия таблиц модуля

Модуль использует ORM битркисА, поэтмоу вам доступны все стандартные события связанные с таблицами:

  • OnBeforeAdd - перед доабвлением
  • OnAfterAdd - после доабвления
  • OnBeforeUpdate - перед обнволением
  • OnAfterUpdate - после обновления
  • OnBeforeDelete - перед удалением
  • OnAfterDelete - после удаления

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

  • \BXmaker\AuthUserPhone\Manager\Limit - лимиты запросов и проверок с привязкой к нмоеру телефона
  • \BXmaker\AuthUserPhone\Manager\Ip\Limit - лимиты запросов и проверок с привязкой к IP
  • \BXmaker\AuthUserPhone\ServiceTable - таблица настроенных подключений к смс сервисам и тому подобное
  • \BXmaker\AuthUserPhone\Service\HistoryTable - таблица текущих проверок, отправленных смс кодов, звонков от роботов и тому подобное

Прмер подписки на событие


$eventManager = \Bitrix\Main\EventManager::getInstance();
$eventManager->addEventHandler(
    "bxmaker.authuserphone",
    "\BXmaker\AuthUserPhone\Manager\Limit::OnBeforeAdd",
    "bxmaker_authuserphone_manager_limit_onBeforeAdd"
);


/**
 * Обработчик события вызываемые перед добавлением записи в таблицу лимитов
 * с привязкой к номеру телефона
 * @param \Bitrix\Main\Entity\Event $event
 * @return \Bitrix\Main\Entity\EventResult
 */
function bxmaker_authuserphone_manager_limit_onBeforeAdd(\Bitrix\Main\Entity\Event $event)
{
    $result = new \Bitrix\Main\Entity\EventResult;

    $fields = $event->getParameter("fields");

    // при добавлении записи в базу, сразу будем считать что человек
    // попытался 5 раз запросить код в смс, но только для определенного
    // нмоера телеофна

    if($fields['PHONE'] == '79991112233')
    {
        $result->modifyFields(array('ATTEMPT_REQUEST_SMS_CODE' => 5));
    }

    return $result;
}

Специальные события модуля

В модуль добавлен целыя ряд событий, которые вы можете использовать для выполнения поставленых задач:

  • onSendCode - вызывается при отправке временного кода в смс, когда нет активного смс сервиса
  • onUserAdd - вызывается после добавлении нового пользователя (при регистраии) для отправки пароля в смс
  • onUserChangePassword - вызывается после смены пароля, для отправки нового пароля
  • onPreparedPhone - вызывается после подготовки номера телефона перед использованием в основной логике
  • onBeforeServiceStartSmsCode - вызывается перед отправкой временного кода в смс, позволяет подменить код в смс
  • onBeforeServiceStartUserCall - вызывается перед началом запроса номера телефона, на который должен позвонить пользователь
  • onBeforeServiceStartBotCall - вызывается перед началом запроса звонка от робота
  • onBeforeAuthorize - вызывается перед авторизацией пользователя, перед вызовом метода CUser::Authorize.
  • onAfterAuthorize- вызывается после авторизации и выполнения прочих зависимых действий, например удаление временных данных, сброс лимитов и тп
  • onChangePhone - вызывается после смены номера телефона, передается идентификатор польвзователя, номер телефона и старый номер телефона

Состав передаваемых парамтеров при вызове событий, а также ожидаймый результат содержится в комментарии к константам содержащим названия событий. Посмотреть подробнее можно в исходных кодах, или в документации к классу Manager.

Ниже приведен пример отправки смс через смс сервис который не встроен в модуль и не поддерживается моделем СМС Оповещений. Модуль в своей работе использует подписку именно на это событие чтобы отправить смс через настроенный сервис.


$eventManager = \Bitrix\Main\EventManager::getInstance();
$eventManager->addEventHandler(
    "bxmaker.authuserphone",
    "onSendCode",
    "bxmaker_authuserphone_onSendCode"
);


function bxmaker_authuserphone_onSendCode(\Bitrix\Main\Event $event)
{
    $fields = (array) $event->getParameter('fields');

    // выбросим исключение, текст которого отобразиться в публичной части
    if ($fields['PHONE'] == '79991112233') {
        throw  new \BXmaker\AuthUserPhone\Exception\BaseException(
            'На ваш номер запрещено отправлять временные коды',
            'ERROR_INVALID_PHONE'
        );
    }

    // или вернем ошибку, чтобы была произведена попытка
    // отправить код через встроенные СМС Сервисис битркиса
    if ($fields['PHONE'] == '79991112244') {
        return new \Bitrix\Main\EventResult(
            \Bitrix\Main\EventResult::ERROR,
            new \Bitrix\Main\Error(
                'Не удалось отправить смс через свой сервис, он недоступен пока'
            )
        );
    }

    //дополним массив парамтеров какими то данными или заменим
    //  больше полезно  в других событиях, н
    //апрмер при старте отправки кода в смс
    if ($fields['PHONE'] == '79991112255') {
        return new \Bitrix\Main\EventResult(
            \Bitrix\Main\EventResult::SUCCESS,
            [
                'TEST' => 1212
            ]
        );
    }

    //отправляем код в смс
    // customSmsSend($fields['PHONE'], 'Временный код - ' . $fields['CODE"]);


    //иначе все ок, не возращаем никакие данные
    return new \Bitrix\Main\EventResult(
        \Bitrix\Main\EventResult::SUCCESS,
        null
    );

}

События компонентов

Во все комопненты добавлены события, котоыре вызваются перед началом обработки ajax запросов. Вараинтов использования этого события множество.

События каждого модуля отличаются:

  • Login - BXmakerAuthuserphoneLoginComponentAjax,BXmakerAuthuserphoneLoginComponentAjaxAnswer
  • Call - BXmakerAuthUserPhoneCallComponentAjax, BXmakerAuthUserPhoneCallComponentAjaxAnswer
  • Edit - BXmakerAuthUserPhoneEditComponentAjax, BXmakerAuthUserPhoneEditComponentAjaxAnswer
  • Simple - BXmakerAuthUserPhoneSimpleComponentAjax, BXmakerAuthUserPhoneSimpleComponentAjaxAnswer
  • Enter - BXmakerAuthUserPhoneEnterComponentAjax, BXmakerAuthUserPhoneEnterComponentAjaxAnswer

В каждом событии передается в списке полей объекты:

  • jsonResponse - Объект класса \BXmaker\AuthUserPhone\Ajax\JsonResponse
  • component - Объект класса компонента в котором вызвано событие

Для примера сделаем возможность автовхода пользователя на сайт без паролей и подтверждений при вводе нмоера телефона 8 (999) 999-99-99. Будем использовать компонент Simple

Для этого разместим обработчик события в файле /bitrix/php_interface/init.php


$eventManager = \Bitrix\Main\EventManager::getInstance();
$eventManager->addEventHandler(
    "bxmaker.authuserphone",
    "BXmakerAuthUserPhoneSimpleComponentAjax",
    "bxmaker_authuserphone_autoauth"
);


function bxmaker_authuserphone_autoauth(\Bitrix\Main\Event $event)
{
    /**
     * @var $jsonResponse \BXmaker\AuthUserPhone\Ajax\JsonResponse
     * @var $component \BXmakerAuthUserPhoneCallComponent
     */
    $fields = $event->getParameter('fields');
    $jsonResponse =  $fields['jsonResponse'];
    $component =  $fields['component'];

    $phone = $component->request()->getPost('phone');

    $phone = $component->manager()->getPreparedPhone($phone);


    if($component->manager()->isValidPhone($phone) && $phone == '79999999999'){


        $findUserResult = $component->manager()->findUserIdByPhone($phone, false);
        if($findUserResult->isSuccess()) {
            $userId = (int) $findUserResult->getResult();
        }
        else {
            $registerResult = $component->manager()->register($phone);
            if(!$registerResult->isSuccess())
            {
                $registerResult->throwException();
            }

            $userId = (int) $registerResult->getResult();
        }


        $authResult = $component->manager()->authorize($userId);
        if(!$authResult->isSuccess())
        {
            $authResult->throwException();
        }

        $component->arParams['IS_ENABLED_RELOAD_AFTER_AUTH'] = 'Y';

        $arResponse = $component->extendResponseAfterAuth($userId, [
            'msg' => 'Вы успешно авторизовались',
            'type' => ($component->manager()->isSetUserRegisterFlag() ? 'REG' : 'AUTH')
        ]);

        $jsonResponse->setResponse($arResponse);
        $jsonResponse->output();

    }

}