Подтверждение номера телефона через смс api

Время прочтения
6 мин

Просмотры 24K

Представим, что перед вами стоит задача организовать аутентификацию пользователя (в мобильном приложении, в первую очередь) так, как это сделано в Telegram/Viber/WhatsApp. А именно реализовать в API возможность осуществить следующие шаги:

  • Пользователь вводит свой номер телефона и ему на телефон приходит СМС с кодом.
  • Пользователь вводит код из СМС и приложение его аутентифицирует и авторизует.
  • Пользователь открывает приложение повторно, и он уже аутентифицирован и авторизован.

Мне потребовалось некоторое количество времени, чтобы осознать, как правильно это сделать. Моя задача — поделиться наработанным с вами в надежде, что это сэкономит кому-то времени.

Я постараюсь кратко изложить выработанный подход к этому вопросу. Подразумевается, что у вас API, HTTPS и, вероятно, REST. Какой у вас там набор остальных технологий неважно. Если интересно — добро пожаловать под кат.

Мы поговорим о тех изменениях, которые следует проделать в API, о том, как реализовать одноразовые пароли на сервере, как обеспечить безопасность (в т.ч. защиту от перебора) и в какую сторону смотреть при реализации это функциональности на мобильном клиенте.

Изменения в API

В сущности требуется добавить три метода в ваше API:

1. Запросить СМС с кодом на номер, в ответ — токен для последующих действий.

Действие соответствует CREATE в CRUD.

    POST /api/sms_authentications/
    Параметры на вход:
        phone
    Параметры на выход:
        token

Если всё прошло, как ожидается, возвращаем код состояния 200.

Если же нет, то есть одно разумное исключение (помимо стандартной 500 ошибки при проблемах на сервере и т.п. — некорректно указан телефон. В этом случае:

HTTP код состояния: 422 (Unprocessable Entity), в теле ответа: PHONE_NUMBER_INVALID.

2. Подтвердить токен с помощью кода из СМС.

Действие соответствует UPDATE в CRUD.

    PUT /api/sms_authentications/<token>/
    Параметры на вход:
        sms_code

Аналогично. Если всё ок — код 200.

Если же нет, то варианты исключений:

  1. Некорректный токен: HTTP код состояния: 404.
  2. Некорректный код: HTTP код состояния: 422 (Unprocessable Entity), в теле ответа: SMS_CODE_INVALID.
  3. Телефон уже подтверждён: HTTP код состояния: 422 (Unprocessable Entity), в теле ответа: ALREADY_CONFIRMED.

3. Форсированная отправка кода повторно.

    PUT /api/sms_authentications/<token>/resend

Аналогично. Если всё ок — код 200.

Если же нет, то варианты исключений:

  1. Некорректный токен: HTTP код состояния: 404.
  2. Слишком частая отправка (скажем, прошлая отправка была не позднее чем 60 секунд назад): HTTP код состояния: 400 (BAD_REQUEST), в теле ответа: TOO_OFTEN.

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

Литература:

  1. Образец для подражания — API Telegram: https://core.telegram.org/methods
  2. Дискуссия на SOF: http://stackoverflow.com/questions/12401255/sms-registration-like-in-the-mobile-app-whatsapp

Особенности реализации одноразовых паролей

Вам потребуется хранить специальный ключ для проверки СМС-кодов. Существует алгоритм TOTP, который, цитирую Википедию:

OATH-алгоритм создания одноразовых паролей для защищенной аутентификации, являющийся улучшением HOTP (HMAC-Based One-Time Password Algorithm). Является алгоритмом односторонней аутентификации — сервер удостоверяется в подлинности клиента. Главное отличие TOTP от HOTP это генерация пароля на основе времени, то есть время является параметром[1]. При этом обычно используется не точное указание времени, а текущий интервал с установленными заранее границами (например, 30 секунд).

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

Пример кода на руби, чтобы было понятно о чём речь:

totp = ROTP::TOTP.new("base32secret3232")
totp.now # => "492039"

# OTP verified for current time
totp.verify("492039") # => true
sleep 30
totp.verify("492039") # => false

Алгоритм описан в стандарте RFC6238, и существует масса реализацией этого алгоритма для многих языков: для Ruby и Rails, для Python, для PHP и т.д..

Строго говоря, Telegram и компания не используют TOTP, т.к. при регистрации там, вас не ограничивают по времени 30-ю секундами. В связи с этим предлагается рассмотреть альтернативный алгоритм OTP, который выдает разные пароли, базируясь на неком счётчике, но не на времени. Встречаем, HOTP:

HOTP (HMAC-Based One-Time Password Algorithm) — алгоритм защищенной аутентификации с использованием одноразового пароля (One Time Password, OTP). Основан на HMAC (SHA-1). Является алгоритмом односторонней аутентификации, а именно: сервер производит аутентификацию клиента.

HOTP генерирует ключ на основе разделяемого секрета и не зависящего от времени счетчика.

HOTP описан в стандарте RFC4226 и поддерживается тем же набором библиотек, что представлен выше. Пример кода на руби:

hotp = ROTP::HOTP.new("base32secretkey3232")
hotp.at(0) # => "260182"
hotp.at(1) # => "055283"
hotp.at(1401) # => "316439"

# OTP verified with a counter
hotp.verify("316439", 1401) # => true
hotp.verify("316439", 1402) # => false

Безопасность решения

Первое непреложное само собой разумеющееся правило: ваше API, где туда-сюда гуляют данные и, самое главное, token должно быть завернуто в SSL. Поэтому только HTTPS, никакого HTTP.

Далее, самым очевидным вектором атаки является прямой перебор. Вот что пишут в параграфе 7.3 авторы стандарта HOTP (на котором базируется TOTP) на эту тему:

Цитата из стандарта

Truncating the HMAC-SHA-1 value to a shorter value makes a brute force attack possible. Therefore, the authentication server needs to detect and stop brute force attacks.

We RECOMMEND setting a throttling parameter T, which defines the maximum number of possible attempts for One-Time Password validation. The validation server manages individual counters per HOTP device in order to take note of any failed attempt. We RECOMMEND T not to be too large, particularly if the resynchronization method used on the server is window-based, and the window size is large. T SHOULD be set as low as possible, while still ensuring that usability is not significantly impacted.

Another option would be to implement a delay scheme to avoid a brute force attack. After each failed attempt A, the authentication server would wait for an increased T*A number of seconds, e.g., say T = 5, then after 1 attempt, the server waits for 5 seconds, at the second failed attempt, it waits for 5*2 = 10 seconds, etc.

The delay or lockout schemes MUST be across login sessions to prevent attacks based on multiple parallel guessing techniques.

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

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

  • Установить задержку после неудачной попытки ввода. Причём увеличивать задержку линейно по числу неудачных попыток. К примеру, после первой попытки — установить задержку в 5 секунд, после второй в 10 и т.п..

Мнение, что можно полагаться только на то, что код живёт ограниченное число секунд, и будет безопасно, т.к. код сбрасывается — ошибочно. Даже, если есть фиксированное ограничение на число попыток в секунду.

Посмотрим на примере. Пусть код TOTP состоит из 6 цифр — это 1000000 возможных вариантов. И пусть разрешено вводить 1 код в 1 секунду, а код живёт 30 секунд.

Шанс, что за 30 попыток в 30 секунд будет угадан код — 3/100000 ~ 0.003%. Казалось бы мало. Однако, таких 30-ти секундных окон в сутках — 2880 штук. Итого, у нас вероятность угадать код (даже несмотря на то, что он меняется) = 1 — (1 — 3/100000)^2880 ~ 8.2%. 10 дней таких попыток уже дают 57.8% успеха. 28 дней — 91% успеха.

Так что надо чётко осознавать, что необходимо реализовать хотя бы одну (а лучше обе) меры, предложенные авторами стандарта.

Не стоит забывать и о стойкости ключа. Авторы в параграфе 4 обязывают длину ключа быть не менее 128 бит, а рекомендованную длину устанавливают в 160 бит (на данный момент неатакуемая длина ключа).

Цитата из стандарта

R6 — The algorithm MUST use a strong shared secret. The length of the shared secret MUST be at least 128 bits. This document RECOMMENDs a shared secret length of 160 bits.

Изменения в схеме БД

Итого, в модели (или в таблице БД, если угодно) надо хранить:

  1. Телефон: phone (советую использовать библиотеки для унификации телефонного номера, вроде этой для Rails),
  2. Ключ для TOTP: otp_secret_key (читаете подробное README для выбранной библиотеки TOTP),
  3. Токен: token (создаете при первом запросе к API чем-нибудь типа SecureRandom),
  4. Ссылку на пользователя: user_id (если у вас есть отдельная таблица/модель, где хранятся данные пользователя).

Особенности реализации мобильного приложения

В случае Android полученный токен можно хранить в SharedPreferences (почему не AccountManager), а для iOS в KeyChain. См. обсуждение на SoF.

Заключение

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

Упростите для пользователей процедуру подтверждения телефона с помощью одноразовых паролей, полученных через СМС

Oct 7, 2019 — Обновлено Jun 4, 2021

Что такое API WebOTP? #

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

Существует множество способов проверки телефонных номеров, но один из наиболее распространенных — случайный одноразовый пароль (OTP), отправленный по СМС. Отправка этого кода обратно на сервер разработчика подтверждает, что данный номер телефона контролируется пользователем.

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

  • Номер телефона как идентификатор пользователя. При подписке на новую услугу некоторые веб-сайты запрашивают номер телефона вместо адреса электронной почты и используют его в качестве идентификатора учетной записи.
  • Двухфакторная проверка. При входе в систему веб-сайт запрашивает одноразовый код, отправленный по СМС, в дополнение к паролю или другому фактору проверки в качестве дополнительной меры безопасности.
  • Подтверждение об оплате. Запрос одноразового кода, отправленного по СМС при совершении платежа, помогает проверить намерение пользователя.

Текущий процесс неудобен пользователям, ведь нужно найти OTP в СМС-сообщениях, затем скопировать его и вставить в форму. Неудобство снижает конверсию на критически важных этапах пути потребителя. Многие крупнейшие мировые разработчики давно просили облегчить эту задачу. Для Android уже существует соответствующий API, как и для iOS и Safari.

API WebOTP позволяет приложению получать специальным образом форматированные сообщения, привязанные к домену приложения. Это делает возможным программное получение OTP из СМС и упрощает проверку номера телефона пользователя.

Практический пример #

Допустим, пользователь хочет подтвердить свой номер телефона на веб-сайте. Веб-сайт отправляет пользователю СМС-сообщение, и пользователь вводит OTP из сообщения, чтобы подтвердить принадлежность номера телефона.

С помощью API WebOTP эти действия выполняются легко, одним нажатием кнопки, как показано в видеоролике. Когда приходит текстовое сообщение, внизу появляется всплывающее окно, предлагающее пользователю подтвердить свой номер телефона. После нажатия кнопки Verify (Подтвердить) в нижнем окне браузер вставляет OTP в форму и происходит отправка, пользователю даже не нужно нажимать Continue (Продолжить).
endAside %}

Весь процесс показан на изображении ниже.

Схема API WebOTP

Запустите демонстрационный пример. Он не запрашивает номер телефона и не отправляет СМС на ваше устройство, но вы можете отправить СМС с другого устройства, скопировав текст, отображаемый в демонстрации. Это работает, потому что при использовании API WebOTP не имеет значения, кто отправитель.

  1. Перейдите на https://web-otp.glitch.me в Chrome 84 или более поздней версии на устройстве Android.
  2. Отправьте на свой телефон следующее СМС-сообщение с другого телефона.
Your OTP is: 123456.

@web-otp.glitch.me #12345

Получили ли вы СМС-сообщение и увидели ли подсказку о необходимости ввести код в поле ввода? Именно так работает API WebOTP для пользователей.

Использование WebOTP API состоит из трех частей:

  • правильно аннотированный тег <input>;
  • JavaScript в вашем веб-приложении;
  • форматированный текст СМС-сообщения.

Начнем с тега <input>.

Аннотируйте тег <input> #

Сам WebOTP работает без какой-либо HTML-аннотации, но для кросс-браузерной совместимости я настоятельно рекомендую добавить autocomplete="one-time-code" в тег <input>, в который пользователь должен ввести OTP.

Это дает возможность Safari 14 или более поздней версии браузера предлагать пользователю автоматически вставить OTP в поле <input> при получении СМС в формате, описанном в разделе «Отформатируйте СМС-сообщение», даже если браузер не поддерживает WebOTP.

HTML

<form>
<input autocomplete="one-time-code" required/>
<input type="submit">
</form>

Используйте API WebOTP #

WebOTP несложный, поэтому просто скопируйте и вставьте следующий код. Далее я подробно объясню работу кода.

JavaScript

if ('OTPCredential' in window) {
window.addEventListener('DOMContentLoaded', e => {
const input = document.querySelector('input[autocomplete="one-time-code"]');
if (!input) return;
const ac = new AbortController();
const form = input.closest('form');
if (form) {
form.addEventListener('submit', e => {
ac.abort();
});
}
navigator.credentials.get({
otp: { transport:['sms'] },
signal: ac.signal
}).then(otp => {
input.value = otp.code;
if (form) form.submit();
}).catch(err => {
console.log(err);
});
});
}

Обнаружение функции #

Обнаружение функции происходит так же, как и для многих других API. Прослушиватель события DOMContentLoaded будет ждать, когда дерево DOM будет готово к запросу.

JavaScript

if ('OTPCredential' in window) {
window.addEventListener('DOMContentLoaded', e => {
const input = document.querySelector('input[autocomplete="one-time-code"]');
if (!input) return;

const form = input.closest('form');

});
}

Обработайте OTP #

Сам API WebOTP достаточно прост. Используйте navigator.credentials.get() для получения OTP. WebOTP добавляет к этому методу новый параметр otp. У него есть только одно свойство: transport, значением которого должен быть массив со строкой 'sms'.

JavaScript


navigator.credentials.get({
otp: { transport:['sms'] }

}).then(otp => {

Это запускает поток разрешений браузера при получении СМС-сообщения. Если разрешение предоставлено, возвращаемое обещание разрешается с помощью объекта OTPCredential.

Содержание полученного объекта OTPCredential

{
code: "123456" // Obtained OTP
type: "otp" // `type` is always "otp"
}

Затем передайте значение OTP в поле <input>. Отправка формы напрямую устранит шаг, требующий от пользователя нажатия кнопки.

JavaScript


navigator.credentials.get({
otp: { transport:['sms'] }

}).then(otp => {
input.value = otp.code;
if (form) form.submit();
}).catch(err => {
console.error(err);
});

Прерывание сообщения #

В случае если пользователь вручную вводит OTP и отправляет форму, вы можете отменить вызов get(), используя экземпляр AbortController в объекте options.

JavaScript


const ac = new AbortController();

if (form) {
form.addEventListener('submit', e => {
ac.abort();
});
}

navigator.credentials.get({
otp: { transport:['sms'] },
signal: ac.signal
}).then(otp => {

Отформатируйте СМС-сообщение #

Сам API выглядит простым, но есть несколько моментов, которые необходимо знать перед его использованием. Сообщение должно быть отправлено после вызова navigator.credentials.get() и должно быть получено на устройстве, на котором была вызвана функция get(). Наконец, сообщение должно соответствовать следующему формату:

  • сообщение начинается с удобочитаемого текста (необязательно), который содержит буквенно-цифровую строку из 4–10 символов с как минимум одной цифрой, а в последней строке указываются URL-адрес и одноразовый пароль (OTP);
  • символ @ должен предшествовать доменной части URL-адреса веб-сайта, вызвавшего API;
  • URL-адрес должен содержать знак решетки (‘ # ‘), за которым следует OTP.

Например:

Your OTP is: 123456.

@www.example.com #123456

Вот плохие примеры:

Демонстрации #

Попробуйте различные сообщения с демонстрацией: https://web-otp.glitch.me

Вы также можете «форкнуть» пример и создать свою версию: https://glitch.com/edit/#!/web-otp.

Используйте WebOTP из iframe с перекрестным происхождением #

Ввод SMS OTP в iframe с перекрестным происхождением обычно используется для подтверждения платежа, особенно с использованием протокола 3D Secure. API WebOTP предоставляет OTP с привязкой к вложенным источникам, используя стандартный формат для поддержки iframes с перекрестным происхождением. Например:

  • Пользователь заходит на сайт shop.example, чтобы купить пару обуви с помощью кредитной карты.
  • После ввода номера кредитной карты интегрированный поставщик платежей показывает форму из bank.example в окне iframe, предлагающую пользователю подтвердить свой номер телефона для быстрой оплаты.
  • bank.example отправляет СМС с OTP пользователю, чтобы он мог ввести OTP для подтверждения своей личности.

Чтобы использовать API WebOTP из iframe с перекрестным происхождением, нужно предпринять следующие два действия:

  • аннотировать в СМС-сообщении источник iframe верхнего уровня и источник iframe;
  • настроить политику разрешений, чтобы разрешить iframe с перекрестным происхождением напрямую получать OTP от пользователя.
API WebOTP в iframe в действии.

Попробуйте демонстрацию на https://web-otp-iframe-demo.stackblitz.io.

Аннотируйте связанные источники (bound-origins) в текстовом СМС-сообщении #

Когда WebOTP API вызывается из iframe, СМС-сообщение в последней строке должно содержать источник iframe верхнего уровня (начинается с символа @), затем OTP (начинается с символа #) и источник iframe (начинается с символа @).

Your verification code is 123456

@shop.example #123456 @bank.exmple

Настройте политику разрешений #

Чтобы использовать WebOTP в iframe с перекрестным происхождением, эмбеддер должен предоставить доступ к этому API через политику разрешений otp-credentials, чтобы избежать непреднамеренного поведения. В общем, есть два способа достичь этой цели:

через заголовок HTTP:

Permissions-Policy: otp-credentials=(self "https://bank.example")

через атрибут allow тега iframe:

<iframe src="https://bank.example/…" allow="otp-credentials"></iframe>

См. другие примеры того, как указать политику разрешений.

Часто задаваемые вопросы #

Диалог не появляется, хотя я отправляю правильно отформатированное сообщение. Что не так? #

При тестировании API учтите следующие моменты:

  • Если номер телефона отправителя включен в список контактов получателя, этот API не будет запускаться из-за конструкции базового API SMS User Consent.
  • Если вы используете рабочий профиль на своем устройстве Android и WebOTP не работает, попробуйте вместо этого установить и использовать Chrome в своем личном профиле (т. е. в том же профиле, в котором вы получаете СМС).

Вернитесь к разделу о формате, чтобы проверить, правильно ли отформатировано ваше СМС.

Обладает ли этот API кросс-браузерной совместимостью? #

Chromium и WebKit согласовали формат текстовых СМС-сообщений, и Apple объявила о его поддержке в Safari, начиная с iOS 14 и macOS Big Sur. Хотя Safari не поддерживает API WebOTP JavaScript, аннотируя input с помощью autocomplete=["one-time-code"], клавиатура по умолчанию автоматически предлагает ввести OTP, если СМС-сообщение соответствует формату.

Насколько безопасно использовать СМС для аутентификации? #

Хотя SMS OTP полезен для проверки номера телефона при его первом предоставлении, следует с осторожностью использовать проверку номера телефона через СМС для повторной аутентификации, поскольку телефонные номера могут быть перехвачены и повторно использованы операторами связи. WebOTP — удобный механизм повторной аутентификации и восстановления доступа, но службы должны сочетать его с дополнительными факторами, такими как аутентификация на основе знаний (KBA), или использовать API Web Authentication для надежной аутентификации.

Куда сообщать об ошибках в реализации Chrome? #

Вы нашли ошибку в реализации Chrome?

  • Сообщите об ошибке на https://new.crbug.com. Укажите как можно больше подробностей, простые инструкции по воспроизведению и установите Components в значение Blink>WebOTP.

Чем я могу помочь с этой функцией? #

Планируете ли вы использовать API WebOTP? Ваша публичная поддержка поможет нам определить приоритетность функций и покажет другим производителям браузеров, насколько важно реализовать поддержку данных функций. Отправьте твит на @ChromiumDev с хештегом #WebOTP и сообщите нам, где и как вы его используете.

Последнее обновление: Jun 4, 2021 — Улучшить статью

Return to all articles

Содержание

  • 1 Верификация телефона по SMS
  • 2 Принцип работы
    • 2.1 Использование SMS шлюза
    • 2.2 HTML форма валидации телефона

Широкое распространение на сайтах коммерческой тематики получили формы обратной связи типа «Заказать звонок». Пользователю сайта предлагается форма с полями: имя и телефон. Заполнив данные, пользователь ждет звонка на указанный номер телефона. А что если пользователь указал не свой телефон?

Или другая ситуация: пользователь сайта забыл свой пароль от учетной записи и в качестве альтернативы желает получить новый пароль на свой номер телефона (указанный в учетной записи). Естественно, он должен знать свой номер телефона и иметь его под рукой, так как SMS придет лишь на прикрепленный телефон.

Подобных ситуаций в современных интернет-реалиях множество, если вы администратор сайта, имеющий дело с учетными записями пользователей, Вам наверняка будет полезной такая функция как подтверждение номера (валидация) мобильного телефона по SMS.

Проверить принадлежность номера телефона пользователю достаточно просто: на номер телефона высылается одноразовый код в SMS сообщении с последующим подтверждением кода на сайте.

Форма для подтверждения телефона по SMS (которую мы сегодня сделаем собственноручно) выглядит примерно следующим образом:

Форма для подтверждения телефона по SMS

Форма для верификации телефона по одноразовому SMS

Принцип работы

Основная цель данного скрипта — проверить введенный пользователем одноразовый пароль, отправленный по SMS на его номер телефона. Если пользователь вводит правильный проверочный код, телефон считается верифицированным, и администратор сайта может продолжить выполнение скриптов. Схематически проверка номера телефона выглядит так:

  1. Пользователь указывает имя и номер телефона;
  2. После нажатия кнопки «Выслать код«, на указанный номер телефона SMS-шлюз высылает сгенерированный числовой пароль — код подтверждения (пароль генерируется исходя из суммы секретной фразы и номера телефона и состоит из 5 цифр);
  3. Скрипт ожидает ввода пользователем кода подтверждения. Скрипт успешно продолжает работу, если пользователь вводит правильный код;

Данный скрипт не является «готовым продуктом», он лишь иллюстрирует механизм верификации телефона по SMS и потребует от Вас его адаптации под конкретные нужды.

Использование SMS шлюза

Прежде всего, нам понадобится SMS шлюз, который будет отправлять SMS. Рекомендую «seozona.sms.ru» (проследуйте по ссылке для регистрации) — у него есть ежедневные бесплатные лимиты, что позволит в целом экономить на отправке SMS. Баланс шлюза всегда держите положительным, чтобы ваши SMS отрабатывали как часики!

После регистрации, в личном кабинете в меню найдите «Программистам», в этой вкладке найдете Ваш api_id. Он вам понадобится далее.

HTML форма валидации телефона

Создадим HTML форму для валидации телефона пользователя: модальное окно, поля для ввода и проверки данных (примерный вид как на скрине выше). Для этого создадим файл index.php c содержимым:

<html>
<head>
<meta charset="UTF-8">
<link rel='stylesheet' href='style.css' type='text/css' media='all' />
<script src="https://code.jquery.com/jquery-1.11.3.min.js"></script>
</head>

<body>
<h1>Верификация телефона с помощью SMS</h1>

<label for="modal-1" id="popup_toggle" style="bottom:25px;right:10px;position:fixed;z-index: 9999;">
<div class="circlephone" style="transform-origin: center;"></div><div class="circle-fill" style="transform-origin: center;"></div><div class="img-circle" style="transform-origin: center;"><div class="img-circleblock" style="transform-origin: center;"></div></div></label>

<div class="modal">
<input class="modal-open" id="modal-1" type="checkbox" hidden>
<div class="modal-wrap" aria-hidden="true" role="dialog">
<label class="modal-overlay" for="modal-1"></label>
<div class="modal-dialog">
<div class="modal-header">
<h3>Верификация телефона по SMS</h3>
<label class="btn-close" for="modal-1" aria-hidden="true">×</label>
</div>
<center><label id="modal-ok">Спасибо. Авторизация прошла успешно</label></center>
<div class="modal-body">
<center>

<form method="post" action="act.php" target="ifr" id="fclose">
<table>
<tr><td>Ваше имя: <td><input name="names" maxlength="25" id=cyr>
<tr><td>Номер телефона: <td><input name="phone" id="input-callback-phone">&nbsp;
<input type="submit" name="sendsms" value="Выслать код" onmousedown="viewDiv()">
<tr><td><br/>
<tr id="div1"><td>Код подтверждения: <td><input name="code" maxlength="7" size="6" onkeyup="if (/D/g.test(this.value)) this.value = this.value.replace(/D/g,'')"> &nbsp; <input type="submit" name="ok" value="Подтвердить код">
<tr><td><br/>
<tr><td>
<td colspan="2" id="_out">
</table>
</form>
<iframe name="ifr" frameborder="0" height="0" width="0" style="visibility:hidden"></iframe>
</center>
</div>
</div>
</div>
</div>

<script type="text/javascript">
$(function() {
jQuery(function($) {
$('#cyr').on('keypress', function() {
var that = this;
setTimeout(function() {
var res = /[^a-zA-Zа-яА-ЯёЁ -]/g.exec(that.value);
that.value = that.value.replace(res, '');
}, 0);
});
});
})
function viewDiv(){
document.getElementById("div1").style.display = "table-row";
};
</script>
<script>!function(a){"function"==typeof define&&define.amd?define(["jquery"],a):a("object"==typeof exports?require("jquery"):jQuery)}(function(a){var b,c=navigator.userAgent,d=/iphone/i.test(c),e=/chrome/i.test(c),f=/android/i.test(c);a.mask={definitions:{9:"[0-9]",a:"[A-Za-z]","*":"[A-Za-z0-9]"},autoclear:!0,dataName:"rawMaskFn",placeholder:"_"},a.fn.extend({caret:function(a,b){var c;if(0!==this.length&&!this.is(":hidden"))return"number"==typeof a?(b="number"==typeof b?b:a,this.each(function(){this.setSelectionRange?this.setSelectionRange(a,b):this.createTextRange&&(c=this.createTextRange(),c.collapse(!0),c.moveEnd("character",b),c.moveStart("character",a),c.select())})):(this[0].setSelectionRange?(a=this[0].selectionStart,b=this[0].selectionEnd):document.selection&&document.selection.createRange&&(c=document.selection.createRange(),a=0-c.duplicate().moveStart("character",-1e5),b=a+c.text.length),{begin:a,end:b})},unmask:function(){return this.trigger("unmask")},mask:function(c,g){var h,i,j,k,l,m,n,o;if(!c&&this.length>0){h=a(this[0]);var p=h.data(a.mask.dataName);return p?p():void 0}return g=a.extend({autoclear:a.mask.autoclear,placeholder:a.mask.placeholder,completed:null},g),i=a.mask.definitions,j=[],k=n=c.length,l=null,a.each(c.split(""),function(a,b){"?"==b?(n--,k=a):i[b]?(j.push(new RegExp(i[b])),null===l&&(l=j.length-1),k>a&&(m=j.length-1)):j.push(null)}),this.trigger("unmask").each(function(){function h(){if(g.completed){for(var a=l;m>=a;a++)if(j[a]&&C[a]===p(a))return;g.completed.call(B)}}function p(a){return g.placeholder.charAt(a<g.placeholder.length?a:0)}function q(a){for(;++a<n&&!j[a];);return a}function r(a){for(;--a>=0&&!j[a];);return a}function s(a,b){var c,d;if(!(0>a)){for(c=a,d=q(b);n>c;c++)if(j[c]){if(!(n>d&&j[c].test(C[d])))break;C[c]=C[d],C[d]=p(d),d=q(d)}z(),B.caret(Math.max(l,a))}}function t(a){var b,c,d,e;for(b=a,c=p(a);n>b;b++)if(j[b]){if(d=q(b),e=C[b],C[b]=c,!(n>d&&j[d].test(e)))break;c=e}}function u(){var a=B.val(),b=B.caret();if(o&&o.length&&o.length>a.length){for(A(!0);b.begin>0&&!j[b.begin-1];)b.begin--;if(0===b.begin)for(;b.begin<l&&!j[b.begin];)b.begin++;B.caret(b.begin,b.begin)}else{for(A(!0);b.begin<n&&!j[b.begin];)b.begin++;B.caret(b.begin,b.begin)}h()}function v(){A(),B.val()!=E&&B.change()}function w(a){if(!B.prop("readonly")){var b,c,e,f=a.which||a.keyCode;o=B.val(),8===f||46===f||d&&127===f?(b=B.caret(),c=b.begin,e=b.end,e-c===0&&(c=46!==f?r(c):e=q(c-1),e=46===f?q(e):e),y(c,e),s(c,e-1),a.preventDefault()):13===f?v.call(this,a):27===f&&(B.val(E),B.caret(0,A()),a.preventDefault())}}function x(b){if(!B.prop("readonly")){var c,d,e,g=b.which||b.keyCode,i=B.caret();if(!(b.ctrlKey||b.altKey||b.metaKey||32>g)&&g&&13!==g){if(i.end-i.begin!==0&&(y(i.begin,i.end),s(i.begin,i.end-1)),c=q(i.begin-1),n>c&&(d=String.fromCharCode(g),j[c].test(d))){if(t(c),C[c]=d,z(),e=q(c),f){var k=function(){a.proxy(a.fn.caret,B,e)()};setTimeout(k,0)}else B.caret(e);i.begin<=m&&h()}b.preventDefault()}}}function y(a,b){var c;for(c=a;b>c&&n>c;c++)j[c]&&(C[c]=p(c))}function z(){B.val(C.join(""))}function A(a){var b,c,d,e=B.val(),f=-1;for(b=0,d=0;n>b;b++)if(j[b]){for(C[b]=p(b);d++<e.length;)if(c=e.charAt(d-1),j[b].test(c)){C[b]=c,f=b;break}if(d>e.length){y(b+1,n);break}}else C[b]===e.charAt(d)&&d++,k>b&&(f=b);return a?z():k>f+1?g.autoclear||C.join("")===D?(B.val()&&B.val(""),y(0,n)):z():(z(),B.val(B.val().substring(0,f+1))),k?b:l}var B=a(this),C=a.map(c.split(""),function(a,b){return"?"!=a?i[a]?p(b):a:void 0}),D=C.join(""),E=B.val();B.data(a.mask.dataName,function(){return a.map(C,function(a,b){return j[b]&&a!=p(b)?a:null}).join("")}),B.one("unmask",function(){B.off(".mask").removeData(a.mask.dataName)}).on("focus.mask",function(){if(!B.prop("readonly")){clearTimeout(b);var a;E=B.val(),a=A(),b=setTimeout(function(){B.get(0)===document.activeElement&&(z(),a==c.replace("?","").length?B.caret(0,a):B.caret(a))},10)}}).on("blur.mask",v).on("keydown.mask",w).on("keypress.mask",x).on("input.mask paste.mask",function(){B.prop("readonly")||setTimeout(function(){var a=A(!0);B.caret(a),h()},0)}),e&&f&&B.off("input.mask").on("input.mask",u),A()})}})});</script>
<script>jQuery( function($){$("#input-callback-phone").mask("+38 (099) 999-99-99");});</script>
</body>
</html>

В этом файле обратим внимание на последние строчки, где указывается маска для ввода телефона. Для Украины: +38 (099) 999-99-99 для России: +7 (999) 999-99-99

И создадим файл со стилями CSS под названием «style.css» (положим его рядом с index.php)

#div1{
display: none;
}
#_out {
color: red;
}
#modal-ok {
display: none;
}
.modal-header h3 {
color: #555;
font-size: 20px;
font-weight: normal;
line-height: 1;
margin: 0;
}
.modal .btn-close {
color: #aaa;
cursor: pointer;
font-size: 50px;
text-decoration: none;
position: absolute;
right: 5px;
top: 0;
}
.modal .btn-close:hover {
color: red;
}
.modal-wrap:before {
content: "";
display: none;
background: rgba(0, 0, 0, .3);
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 101;
}
.modal-overlay {
bottom: 0;
display: none;
left: 0;
position: fixed;
right: 0;
top: 0;
z-index: 102;
}
.modal-open:checked ~ .modal-wrap:before,
.modal-open:checked ~ .modal-wrap .modal-overlay {
display: block;
}
.modal-open:checked ~ .modal-wrap .modal-dialog {
-webkit-transform: translate(-50%, 0);
-ms-transform: translate(-50%, 0);
-o-transform: translate(-50%, 0);
transform: translate(-50%, 0);
top: 20%;
}
.modal-dialog {
background: #fefefe;
border: none;
border-radius: 5px;
position: fixed;
width: 80%;
max-width: 500px;
left: 50%;
top: -100%;
-webkit-box-shadow: 0 15px 20px rgba(0,0,0,.22),0 19px 60px rgba(0,0,0,.3);
-moz-box-shadow: 0 15px 20px rgba(0,0,0,.22),0 19px 60px rgba(0,0,0,.3);
box-shadow: 0 15px 20px rgba(0,0,0,.22),0 19px 60px rgba(0,0,0,.3);
-webkit-transform: translate(-50%, -500%);
-ms-transform: translate(-50%, -500%);
-o-transform: translate(-50%, -500%);
transform: translate(-50%, -500%);
-webkit-transition: -webkit-transform 0.4s ease-out;
-moz-transition: -moz-transform 0.4s ease-out;
-o-transition: -o-transform 0.4s ease-out;
transition: transform 0.4s ease-out;
z-index: 103;
}
.modal-body {
padding: 20px;
}
.modal-body p {
margin: 0;
}
.modal-header,
.modal-footer {
padding: 20px 20px;
}
.modal-header {
border-bottom: #eaeaea solid 1px;
}
.modal-header h3 {
font-size: 20px;
margin: 0;
}
.btn {
background: #fff;
border: #555 solid 1px;
border-radius: 3px;
cursor: pointer;
display: inline-block;
font-size: 14px;
padding: 8px 15px;
text-decoration: none;
text-align: center;
min-width: 60px;
position: relative;
color: #2870a0;
}
.btn:hover, .btn:focus {
background: #f2f2f2;
color: #000000;
text-decoration: underline;
}
.btn-primary {
background: #428bca;
border-color: #357ebd;
color: #2870a0;
}
.btn-primary:hover{
background: #66A1D3;
text-decoration: underline;
}
.img-circle{background-color:#f2b026;box-sizing:content-box;-webkit-box-sizing:content-box;}
.circlephone{box-sizing:content-box;-webkit-box-sizing:content-box;border: 2px solid #f2b026;width:150px;height:150px;bottom:-25px;right:10px;position:absolute;-webkit-border-radius:100%;-moz-border-radius: 100%;border-radius: 100%;opacity: .5;-webkit-animation: circle-anim 2.4s infinite ease-in-out !important;-moz-animation: circle-anim 2.4s infinite ease-in-out !important;-ms-animation: circle-anim 2.4s infinite ease-in-out !important;-o-animation: circle-anim 2.4s infinite ease-in-out !important;animation: circle-anim 2.4s infinite ease-in-out !important;-webkit-transition: all .5s;-moz-transition: all .5s;-o-transition: all .5s;transition: all 0.5s;}
.circle-fill{box-sizing:content-box;-webkit-box-sizing:content-box;background-color:#f2b026;width:100px;height:100px;bottom:0px;right:35px;position:absolute;-webkit-border-radius: 100%;-moz-border-radius: 100%;border-radius: 100%;border: 2px solid transparent;-webkit-animation: circle-fill-anim 2.3s infinite ease-in-out;-moz-animation: circle-fill-anim 2.3s infinite ease-in-out;-ms-animation: circle-fill-anim 2.3s infinite ease-in-out;-o-animation: circle-fill-anim 2.3s infinite ease-in-out;animation: circle-fill-anim 2.3s infinite ease-in-out;-webkit-transition: all .5s;-moz-transition: all .5s;-o-transition: all .5s;transition: all 0.5s;}
.img-circle{box-sizing:content-box;-webkit-box-sizing:content-box;width:72px;height:72px;bottom: 14px;right: 49px;position:absolute;-webkit-border-radius: 100%;-moz-border-radius: 100%;border-radius: 100%;border: 2px solid transparent;opacity: .7;}
.img-circleblock{box-sizing:content-box;-webkit-box-sizing:content-box;width:72px;height:72px;background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABcAAAAnCAMAAADTjiM/AAAAkFBMVEUAAAD///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////+WABnwAAAAL3RSTlMA/F/uDUwjB/esmHJTRjPl39fRzr+6sqeijn0E8cnEtq+FeWtjKh4YFdaciIE5FLd9ggsAAAEESURBVCjPbdPpdoIwEAVgQlgEZEdWrVat2vW+/9u1dJLDMO38/C4nZ2ZCHKqgL/WH86eSHIAOhHotAAW4ghvgN4hWHHbECurO3YVxhSv/vIQJgJb5BdYVctZRx5x3dAQrf/Hdojs+wBPZpkqyibdZkz/L1RzIt9IbqNkT6R35WfpAPkgfTY+h8FSp2Yub8EArGlV4WEH9O0BMXk3Ct2YRqfBbTkEvD4rI9y/CfUVBLHwyq9aZCFxQNeE8z+XdHujVJhiy61EDtcdapWbFDxnZgPzNerYHL/1YlrGq1LoXrfzk2Hq8ci++lvvZ8MBley2Yj2zs+7m0fPhcvyh/7E9tnPzc6Tc7fz7JKsL/WwAAAABJRU5ErkJggg==');background-position: center center;background-repeat:no-repeat;animation-name: tossing;-webkit-animation-name: tossing;animation-duration: 1.5s;-webkit-animation-duration: 1.5s;animation-iteration-count: infinite;-webkit-animation-iteration-count: infinite;}
.img-circle:hover{opacity: 1;}
@keyframes pulse {0% {transform: scale(0.9);opacity: 1;}
50% {transform: scale(1); opacity: 1; }
100% {transform: scale(0.9);opacity: 1;}}
@-webkit-keyframes pulse {0% {-webkit-transform: scale(0.95);opacity: 1;}
50% {-webkit-transform: scale(1);opacity: 1;}
100% {-webkit-transform: scale(0.95);opacity: 1;}}
@keyframes tossing {
0% {transform: rotate(-8deg);}
50% {transform: rotate(8deg);}
100% {transform: rotate(-8deg);}}
@-webkit-keyframes tossing {
0% {-webkit-transform: rotate(-8deg);}
50% {-webkit-transform: rotate(8deg);}
100% {-webkit-transform: rotate(-8deg);}}
@-moz-keyframes circle-anim {
0% {-moz-transform: rotate(0deg) scale(0.5) skew(1deg);opacity: .1;-moz-opacity: .1;-webkit-opacity: .1;-o-opacity: .1;}
30% {-moz-transform: rotate(0deg) scale(0.7) skew(1deg);opacity: .5;-moz-opacity: .5;-webkit-opacity: .5;-o-opacity: .5;}
100% {-moz-transform: rotate(0deg) scale(1) skew(1deg);opacity: .6;-moz-opacity: .6;-webkit-opacity: .6;-o-opacity: .1;}}
@-webkit-keyframes circle-anim {
0% {-webkit-transform: rotate(0deg) scale(0.5) skew(1deg);-webkit-opacity: .1;}
30% {-webkit-transform: rotate(0deg) scale(0.7) skew(1deg);-webkit-opacity: .5;}
100% {-webkit-transform: rotate(0deg) scale(1) skew(1deg);-webkit-opacity: .1;}}
@-o-keyframes circle-anim {
0% {-o-transform: rotate(0deg) kscale(0.5) skew(1deg);-o-opacity: .1;}
30% {-o-transform: rotate(0deg) scale(0.7) skew(1deg);-o-opacity: .5;}
100% {-o-transform: rotate(0deg) scale(1) skew(1deg);-o-opacity: .1;}}
@keyframes circle-anim {
0% {transform: rotate(0deg) scale(0.5) skew(1deg);opacity: .1;}
30% {transform: rotate(0deg) scale(0.7) skew(1deg);opacity: .5;}
100% {transform: rotate(0deg) scale(1) skew(1deg);
opacity: .1;}}
@-moz-keyframes circle-fill-anim {
0% {-moz-transform: rotate(0deg) scale(0.7) skew(1deg);opacity: .2;}
50% {-moz-transform: rotate(0deg) -moz-scale(1) skew(1deg);opacity: .2;}
100% {-moz-transform: rotate(0deg) scale(0.7) skew(1deg);opacity: .2;}}
@-webkit-keyframes circle-fill-anim {
0% {-webkit-transform: rotate(0deg) scale(0.7) skew(1deg);opacity: .2; }
50% {-webkit-transform: rotate(0deg) scale(1) skew(1deg);opacity: .2; }
100% {-webkit-transform: rotate(0deg) scale(0.7) skew(1deg);opacity: .2;}}
@-o-keyframes circle-fill-anim {
0% {-o-transform: rotate(0deg) scale(0.7) skew(1deg);opacity: .2;}
50% {-o-transform: rotate(0deg) scale(1) skew(1deg);opacity: .2;}
100% {-o-transform: rotate(0deg) scale(0.7) skew(1deg);opacity: .2;}}
@keyframes circle-fill-anim {
0% {transform: rotate(0deg) scale(0.7) skew(1deg);opacity: .2;}
50% {transform: rotate(0deg) scale(1) skew(1deg);opacity: .2;}
100% {transform: rotate(0deg) scale(0.7) skew(1deg);opacity: .2;}}

Обработчик подтверждения номера телефона по SMS вынесем в отдельный файл «act.php«. Его содержимое:

<?php
$api_id = "bs13a379-8599-c8e4-151d-5c4db6803dcc"; // Ваш api_id в sms.ru - берется в кабинете по ссылке ПРОГРАММИСТАМ
$secretfrase="moyafraza"; // секретная фраза для перегенерации уникального кода для телефонов
$tomail = "[email protected]"; //мыло админа для отчета
$tophone = "795577984612"; //телефон админа для отчета
$tophone_sms = 1; // отправлять СМС админу = 0 - чтобы выключить
$tomail_sms = 1; // отправлять мыло админу = 0 - чтобы выключить

//ДАЛЬШЕ ТРОГАЕМ ЛИШЬ В СЛУЧАЕ ОСТРОЙ НЕОБХОДИМОСТИ

//обрабатываем последствия валидации номера
$sms_tel = preg_replace("/[^0-9]/", '', $_POST["phone"]);

echo "<script>parent.document.getElementById('_out').innerHTML = '";
//Заменяем пробелы в имени если указано ФИО
$sms_imeno = str_replace(' ','+', $_POST["names"]);

if (isset($_POST["sendsms"])) {

if (iconv_strlen($sms_tel)!==12) {
echo "Неверный номер телефона<br>";
echo "'</script>";
exit;
}

//отсылаем код
$body = file_get_contents("https://sms.ru/sms/send?api_id=".$api_id."&to=".$sms_tel."&msg=".ok_code($sms_tel)."&partner_id=17254&json=1");
$json = json_decode($body);
if ($json) { // Получен ответ от сервера
//print_r($json); // Для дебага
if ($json->status == "OK") {
foreach ($json->sms as $phone => $data) {
if ($data->status == "OK") {
echo "Код на номер $phone УСПЕШНО ОТПРАВЛЕН. ";
} else { // Ошибка в отправке
echo "Код на номер $phone НЕ ОТПРАВЛЕН. $data->status_text. ";
}
}
} else {
echo "Запрос не выполнился: $json->status_code. ";
}
} else {
echo "Запрос не выполнился. Не удалось установить связь с сервером. ";
}
echo "'</script>";
}

if (isset($_POST["ok"])) {
$oc = ok_code($sms_tel);
if ($oc == $_POST["code"]) { //если введенный код совпал с тем, что генерируется

//отправляем SMS админу
if ($tophone_sms == 1) {
$body = file_get_contents("https://sms.ru/sms/send?api_id=".$api_id ."&to=".$tophone."&msg=".$sms_imeno."+".$sms_tel."&partner_id=17254");
}

//отправляем на почту админу
if ($tomail_sms == 1) {
$headers = "MIME-Version: 1.0rn";
$headers .= "Content-type: text/html; charset=UTF-8rn";
$headers .= "From: ".$_POST["names"]." <".$_POST["phone"].">"."n";
$sub = "Заказ звонка";
$mes = "Заказан звонок от: ".$_POST["names"].": ".$_POST["phone"]."n";
mail($tomail, $sub, $mes, $headers);
}
echo "'; parent.document.getElementById('fclose').style.display="none"; parent.document.getElementById('modal-ok').style.display="block"; </script>";
}
else
{ echo "Неверный код подтверждения";
echo "'</script>";
}
}

function ok_code($s) {
global $secretfrase;
$tel_plus_secret=$s.$secretfrase;
return hexdec(substr(md5($tel_plus_secret), 4, 4));
}
?>

В обработчике формы обратите внимание на конфигурацию параметров в первых строках: необходимо указать:

  • ваш api_id из личного кабинета SMS шлюза;
  • ваш номер телефона;
  • вашу почту;
  • возможность получения отчета по SMS или email (опционально);

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

To automatically verify phone numbers, you must implement both the client and
server portions of the verification flow. This document describes how to
implement the client portion in an Android app.

To start the phone number verification flow in an Android app, you send the
phone number to your verification server and call the SMS Retriever API to begin
listening for an SMS message containing a one-time code for your app. After you
receive the message, you send the one-time code back to your server to complete
the verification process.

Before you begin

To prepare your app, complete the steps in the following sections.

App prerequisites

Make sure that your app’s build file uses the following values:

  • A minSdkVersion of 19 or higher
  • A compileSdkVersion of 28 or higher

Configure your app

In your project-level build.gradle file, include Google’s Maven repository
and Maven central repository
in both your buildscript and allprojects sections:

buildscript {
    repositories {
        google()
        mavenCentral()
    }
}

allprojects {
    repositories {
        google()
        mavenCentral()
    }
}

Add the Google Play services dependency
for the SMS Retriever API to your module’s Gradle build file,
which is commonly app/build.gradle:

dependencies {
  implementation 'com.google.android.gms:play-services-auth:20.4.1'
  implementation 'com.google.android.gms:play-services-auth-api-phone:18.0.1'
}

1. Obtain the user’s phone number

You can obtain the user’s phone number in whatever way is appropriate for your
app. Often, it is the best user experience to use the hint picker to prompt the
user to choose from the phone numbers stored on the device and thereby avoid
having to manually type a phone number. To use the hint picker:

// Construct a request for phone numbers and show the picker
private void requestHint() {
    HintRequest hintRequest = new HintRequest.Builder()
           .setPhoneNumberIdentifierSupported(true)
           .build();

    PendingIntent intent = Auth.CredentialsApi.getHintPickerIntent(
            apiClient, hintRequest);
    startIntentSenderForResult(intent.getIntentSender(),
            RESOLVE_HINT, null, 0, 0, 0);
}

// Obtain the phone number from the result
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
  super.onActivityResult(requestCode, resultCode, data);
  if (requestCode == RESOLVE_HINT) {
      if (resultCode == RESULT_OK) {
          Credential credential = data.getParcelableExtra(Credential.EXTRA_KEY);
          // credential.getId();  <-- will need to process phone number string
      }
  }
}

2. Start the SMS retriever

When you are ready to verify the user’s phone number, get an instance of the
SmsRetrieverClient object, call startSmsRetriever, and attach success and
failure listeners to the SMS retrieval task:

// Get an instance of SmsRetrieverClient, used to start listening for a matching
// SMS message.
SmsRetrieverClient client = SmsRetriever.getClient(this /* context */);

// Starts SmsRetriever, which waits for ONE matching SMS message until timeout
// (5 minutes). The matching SMS message will be sent via a Broadcast Intent with
// action SmsRetriever#SMS_RETRIEVED_ACTION.
Task<Void> task = client.startSmsRetriever();

// Listen for success/failure of the start Task. If in a background thread, this
// can be made blocking using Tasks.await(task, [timeout]);
task.addOnSuccessListener(new OnSuccessListener<Void>() {
  @Override
  public void onSuccess(Void aVoid) {
    // Successfully started retriever, expect broadcast intent
    // ...
  }
});

task.addOnFailureListener(new OnFailureListener() {
  @Override
  public void onFailure(@NonNull Exception e) {
    // Failed to start retriever, inspect Exception for more details
    // ...
  }
});

The SMS retrieval task will listen for up to five minutes for an SMS message
that contains a unique string that identifies your app.

3. Send the phone number to your server

After you have obtained the user’s phone number and started to listen for SMS
messages, send the user’s phone number to your verification server using any
method (usually with an HTTPS POST request).

Your server generates a verification message and sends it by SMS to the phone
number you specified. See Perform SMS Verification on the Server.

4. Receive verification messages

When a verification message is received on the user’s device, Play services
explicitly broadcasts to your app a SmsRetriever.SMS_RETRIEVED_ACTION Intent,
which contains the text of the message. Use a BroadcastReceiver to receive
this verification message.

In the BroadcastReceiver‘s onReceive handler, get the text of the
verification message from the Intent’s extras:

/**
 * BroadcastReceiver to wait for SMS messages. This can be registered either
 * in the AndroidManifest or at runtime.  Should filter Intents on
 * SmsRetriever.SMS_RETRIEVED_ACTION.
 */
public class MySMSBroadcastReceiver extends BroadcastReceiver {

  @Override
  public void onReceive(Context context, Intent intent) {
    if (SmsRetriever.SMS_RETRIEVED_ACTION.equals(intent.getAction())) {
      Bundle extras = intent.getExtras();
      Status status = (Status) extras.get(SmsRetriever.EXTRA_STATUS);

      switch(status.getStatusCode()) {
        case CommonStatusCodes.SUCCESS:
          // Get SMS message contents
          String message = (String) extras.get(SmsRetriever.EXTRA_SMS_MESSAGE);
          // Extract one-time code from the message and complete verification
          // by sending the code back to your server.
          break;
        case CommonStatusCodes.TIMEOUT:
          // Waiting for SMS timed out (5 minutes)
          // Handle the error ...
          break;
      }
    }
  }
}

Register this BroadcastReceiver with the intent filter
com.google.android.gms.auth.api.phone.SMS_RETRIEVED (the value of the
SmsRetriever.SMS_RETRIEVED_ACTION constant) and the permission
com.google.android.gms.auth.api.phone.permission.SEND (the value of the
SmsRetriever.SEND_PERMISSION constant) in your app’s AndroidManifest.xml
file, as in the following example, or dynamically using Context.registerReceiver.

<receiver android:name=".MySMSBroadcastReceiver" android:exported="true"
          android:permission="com.google.android.gms.auth.api.phone.permission.SEND">
    <intent-filter>
        <action android:name="com.google.android.gms.auth.api.phone.SMS_RETRIEVED"/>
    </intent-filter>
</receiver>

5. Send the one-time code from the verification message to your server

Now that you have the text of the verification message, use a regular expression
or some other logic to get the one-time code from the message. The format of the
one-time code depends on how you implemented them in your server.

Finally, send the one-time code to your server over a secure connection. When
your server receives the one-time code, it records that the phone number has
been verified.

Optional: Save the phone number with Smart Lock for Passwords

Optionally, after the user has verified their phone number, you can prompt the
user to save this phone number account with Smart Lock for Passwords so it will
be available automatically in other apps and on other devices without having to
type or select the phone number again:

Credential credential = new Credential.Builder(phoneNumberString)
        .setAccountType("https://signin.example.com")  // a URL specific to the app
        .setName(displayName)  // optional: a display name if available
        .build();
Auth.CredentialsApi.save(apiClient, credential).setResultCallback(
            new ResultCallback() {
                public void onResult(Result result) {
                    Status status = result.getStatus();
                    if (status.isSuccess()) {
                        Log.d(TAG, "SAVE: OK");  // already saved
                    } else if (status.hasResolution()) {
                        // Prompt the user to save
                        status.startResolutionForResult(this, RC_SAVE);
                    }
                }
            });

Then, after the user reinstalls the app or installs the app on a new device, you
can retrieve the saved phone number without having ask the user again for their
phone number:

// On the next install, retrieve the phone number
mCredentialRequest = new CredentialRequest.Builder()
    .setAccountTypes("https://signin.example.com")  // the URL specific to the developer
    .build();
Auth.CredentialsApi.request(apiClient, mCredentialRequest).setResultCallback(
    new ResultCallback<CredentialRequestResult>() {
        public void onResult(CredentialRequestResult credentialRequestResult) {
            if (credentialRequestResult.getStatus().isSuccess()) {
                credentialRequestResult.getCredential().getId();  // this is the phone number
            }
        }
    });

// Then, initiate verification and sign the user in (same as original verification logic)

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

Подскажите, как это возможно реализовать?

Nicolas Chabanovsky's user avatar

задан 16 ноя 2015 в 19:47

Android Master's user avatar

2

Заключаешь договор с SMS-шлюзом. Например, sms.ru или smsc.ru (Не реклама!)
У них есть API, к которому можно обращаться post-запросом.

1.Формируешь на стороне сервера уникальный код

2.Передаешь его в api с указанием номера клиента.
Примерно так:

curl "http://IpOfService/sendsms.cgi?http_username=YouUsername&http_password=YourPassword&phone_list=CustomerNumber&fromphone=NameOfYouService&message=$Нужные$Данные"

3.Клиент получил код подтверждения.

4.Проверяешь код на соответствие отправленному.

P.S. Проще вообще некуда. Хоть вручную по запросу дергать ссылку на API.

alex-rudenkiy's user avatar

alex-rudenkiy

4,0122 золотых знака17 серебряных знаков34 бронзовых знака

ответ дан 5 мар 2016 в 16:07

Alexandr Blinov's user avatar

Для этой задачи вам не обойтись без сторонних сервисов. Быстрый поиск в гугле выдает много результатов. Например, https://checkmobi.com/

ответ дан 23 ноя 2015 в 15:38

Daniels Šatcs's user avatar

Daniels ŠatcsDaniels Šatcs

1,6019 серебряных знаков15 бронзовых знаков

Вступление

В предыдущем епизоде, я писал о подготовке вашего приложение к SMS используя Twilio, широко-распрастраненый сервис SMS. В сегоднешнем туториале я вам покажу как подтвердить номер мобильного телефона пользователя, перед тем как отправлять большие объемы текста, которые быстро превысят ваши затраты.

Перед тем как мы начнем, мне хотелось бы попросить вас оставлять ваши вопросы и отзывы в коментариях. Если вы хотели что-бы я продолжил свое будущее на Envato Tuts+, писав туториалы и другие серии, пожалуйста посетите мою страницу иструктора или подпишитесь на @lookahead_io.

Описание Процесса

После того, как пользователь введет свой мобильный номер, нам нужно будет произвести немного действий:

  • Генерирование униклаьного 4-х циферного кода.
  • Сохранение их мобильного номера и 4-х циферного кода в базе данных ( или зашифровать код в локальном хранилище как скрытую переменную формы на странице )
  • Отправить SMS не проверенному номеру с 4-х символьным кодом.
  • Отобразить форму, запрашивающию код, который они получили.
  • Проверить совпадение кода.
  • Обозначить номер как «проверенный» в базе данных.

Страница контактов пользователя.

В Meeting Planner, каждый пользователь может добавлять несколько котнактных данных, например Skpye, телефон и т.д. Каждый мобильный номер должен быть проверен перед использование SMS оповещений.

Третья строка снизу показывает чекбокс, который пользователь может нажать что-бы запросить проверку.

How to Verify a Phone Number via SMS - Contacts listHow to Verify a Phone Number via SMS - Contacts listHow to Verify a Phone Number via SMS - Contacts list

При нажатии, пользователь попадает на actionVerify() контроллер снизу; заметьте, что сначало это переносит их на else блок, так-как код не был сначала отправлен.

1
public function actionVerify($id)
2
{
3
    $model = $this->findModel($id);
4
    if ($model->load(Yii::$app->request->post())) {
5
    ...
6
    } else {
7
      $canRequest = $model->canRequest();
8
      if ($canRequest) {
9
        // send a text to this number

10
        $model->requestCode();
11
        return $this->render('verify', [
12
            'model' => $model,
13
        ]);
14
      } else {
15
        Yii::$app->getSession()->setFlash('error', $canRequest);
16
        return $this->redirect(['/user-contact']);
17
      }
18
    }
19
}

Метод canRequest() проверяет запрашивает-ли пользователь код слишком часто или нет

1
public function canRequest() {
2
    if ($this->request_count<UserContact::MAX_REQUEST_COUNT) {
3
      if (time() - $this->requested_at>=60) {
4
        return true;
5
      } else {
6
          return Yii::t('frontend','Sorry, you must wait a minute between requests.');
7
      }
8
    } else {
9
      return Yii::t('frontend','You have exceeded the maximum number of attempts.');
10
    }
11
  }

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

Передача кода подтверждения.

Если это разрешено, он вызывет requestCode()

1
public function requestCode() {
2
    $this->verify_code = rand(0,9999);
3
    $this->requested_at = time();
4
    $this->request_count+=1;
5
    $this->update();
6
    $sms = new Sms;
7
    $sms->transmit($this->info,Yii::t('frontend',
8
        'Please return to the site and type in {code}',['code'=>sprintf("%04d",$this->verify_code)]));
9
  }

Это делает следующие:

  • Генерирует рандомный 4-х чисельный код.
  • Записывает момент времени в Unix секундах, когда данный запрос был сделан.
  • Увеличивает на 1 количество попыток проверки для данного номера.
  • И сохраняет это все в базе данных.
  • После чего он отправляет код в SMS сообщении, которое выглядит как на картинку снизу.

How to Verify a Phone Number via SMS - Text message with verification codeHow to Verify a Phone Number via SMS - Text message with verification codeHow to Verify a Phone Number via SMS - Text message with verification code

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

How to Verify a Phone Number via SMS - Verify Contact Form requesting codeHow to Verify a Phone Number via SMS - Verify Contact Form requesting codeHow to Verify a Phone Number via SMS - Verify Contact Form requesting code

Проверка Кода

Когда пользователь пытается отправить код, ему возвращается верхняя часть actionVerify():

1
public function actionVerify($id)
2
{
3
    $model = $this->findModel($id);
4
    if ($model->load(Yii::$app->request->post())) {
5
        // display verification form
6
        $model->verify = Yii::$app->request->post()['UserContact']['verify'];
7
        if (strval($model->verify_code) == strval($model->verify)) {
8
          $model->status = UserContact::STATUS_VERIFIED;
9
          $model->update();
10
          Yii::$app->getSession()->setFlash('success',Yii::t('frontend','Thank you, your number is confirmed.'));
11
          return $this->redirect(['/user-contact']);
12
        } else {
13
            Yii::$app->getSession()->setFlash('error', Yii::t('frontend','Sorry, that is incorrect. Please request a new code.'));
14
            return $this->redirect(['/user-contact']);
15
        }
16
    } else {
17
      ...
18
    }
19
}

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

How to Verify a Phone Number via SMS - Successful confirmation noticeHow to Verify a Phone Number via SMS - Successful confirmation noticeHow to Verify a Phone Number via SMS - Successful confirmation notice

Если не совпадает, он отображает сообщение об ошибке:

How to Verify a Phone Number via SMS - Error try again after a minuteHow to Verify a Phone Number via SMS - Error try again after a minuteHow to Verify a Phone Number via SMS - Error try again after a minute

Попробуйте Сами

Если вы хотите увидить это в действии, вы можете зарегестрироваться на Simple Planner или Meeting Planner ( который дружит с социальными сетями типо Facebook или Google ) и добавить мобильный номер. После чего нажать на чекбокс в данном списке.

Итоги

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

Я надеюсь вы нашли данный туториал полезным. Если у вас есть вопросы или предложения, пожалуйста оставте их в коментариях. Если вы хотите следить за моим будующим на Envato Tuts+ туториалов и других серий, пожалуйста поситите мою страницу инструктора или подпишитесь на @lookahead_io. Вам также определенно стоит посмотреть мою серию Стартапов и Meeting Planner.

Ссылке по теме

  • Подготовка к отправке SMS сообщений (Envato Tuts+)
  • Серия по програмированию с Yii2 (Evanto Tuts+)
  • Yii2 Developer Exchange

C:UsersЕленаDocumentsПланSMS-АссистентИсходникиЛого и конвертыOtpiska.jpg

Форма для подтверждения номера телефона

Для подтверждения номера мобильного телефона посетителя сайта, например, для активации новой учетной записи на сайте, или при оставлении комментария, можно использовать подтверждение номера телефона с помощью SMS-кода.

Описание принципа действия

  1. Пользователь вводит свой номер мобильного телефона.
  2. Нажимает кнопку [Выслать код].
  3. В этот момент генерируется код, состоящий из 5 цифр, который отправляется в виде SMS-сообщения через сервис www.sms-assistent.by на указанный номер мобильного телефона. Код генерируется безопасно, в браузере не хранится, поэтому его не могут подсмотреть злоумышленники.
  4. Пользователь вводит код, нажимает [Подтвердить].
  5. Происходит сверка введённого кода с отправленным. Если код верен, телефон считается идентифицированным (подтверждённым). Вы получаете результат проверки, и можете дальше разрешать пользователю совершать те или иные действия (оставить комментарий, зарегистрироваться и т.д.).

Возможности предлагаемого готового решения

  1. Готовая HTML-форма

для вставки на свой интернет-ресурс. Стили формы вынесены в отдельный файл, что позволяет легко редактировать их под себя.

  1. Ввод телефонного номера абонентов Республики Беларусь в любом формате:

81037529xxxxxxx

375029xxxxxxx

37529xxxxxxx

+37529xxxxxxx

8029xxxxxxx

029xxxxxxx

29xxxxxxx

* xxxxxxx — семизначный номер абонента. Вместо кода 29 возможны другие коды мобильных операторов РБ (33, 44, 25).

Все другие символы, кроме цифр, не учитываются.

  1. Автоматическая проверка на правильность номера телефона

после ввода номера в форму. Учитывается корректность длины номера, принадлежность диапазонам мобильных операторов Республики Беларусь. Городские номера, короткие/длинные, не существующие в номерном фонде операторов, будут признаны некорректными, благодаря чему, отправка SMS на такие номера происходить не будет. Телефоны других стран проверяются на принадлежность стране, некоторые проверяются на диапазоны операторов.[1] 

  1. Возможность в тексте SMS добавить к коду подтверждения свой текст,

например, адрес своего сайта или другую дополнительную информацию.

  1. Результат ввода данных отображается на экране − у пользователя будет “обратная связь” после выполнения своих действий.
  2. Лимит отправляемых SMS с одной формы на один и тот же номер телефона. По умолчанию установлен на 5 SMS за 60 минут. Вы сможете самостоятельно регулировать это значение[2].
  3. Лимит времени, отведённый на ввод кода из SMS. По умолчанию установлен на 5 минут.
    Вы сможете самостоятельно регулировать это значение
    2.
  4. Очистка данных, введённых в форму после успешного подтверждения номера телефона.
  5. Результат подтверждения номера телефона в виде “Ok + номер телефона”. В случае подтверждения номера телефона, в ответ вам возвращается статус “Оk” и  непосредственно сам номер телефона, который вы можете записывать в свою базу данных для хранения информации о пользователе.
  6. Встроенный обработчик результатов проверки позволяет вам производить дальнейшие действия с пользователем (разрешить оставить комментарий, получить доступ к ресурсу, скачать файл и т.д.).

Прежде чем начать

  1. Зарегистрируйтесь!

Вам необходимо быть зарегистрированным пользователем сервиса SMS-ассистент (только для ИП и юридических лиц Республики Беларусь). Для этого вы можете зарегистрироваться на демо-версию или получить полный доступ.

  1. Подключите API в Личном кабинете

!

Если вы не активируете API в разделе «SMS-рассылка → Рассылка по API», то в ответ на запрос вам будет возвращаться ошибка «−10».

Если вы не сгенерируете персональный пароль для API, то в ответ на запрос вам будет возвращаться ошибка «−2». Если после подключения вы всё равно получаете эту ошибку, то воспользуйтесь рекомендациями по самостоятельному анализу ошибки.

  1. Сохраните ваши персональные данные

  • Логин – название аккаунта для входа (отправлялся вам на телефон в виде SMS).
  • Пароль – персональный пароль для API (генерируется на предыдущем шаге).

Если вы забыли ваш логин, то вы можете его восстановить. Для этого на странице авторизации в программу воспользуйтесь опцией «Забыли логин и/или пароль?». Введите ваш e-mail и УНП. На телефонный номер, указанный при регистрации, придёт SMS с логином и новым паролем для входа в личный кабинет.

Если вы забыли пароль для API, то после входа в аккаунт, на странице «SMS-рассылка →  Рассылка по API» сгенерируйте новый персональный пароль для API (описано на предыдущем шаге).

Обратите особое внимание: этот новый сгенерированный пароль вам необходимо будет вводить в настройки формы для подтверждения номера телефона.

  1. Проверьте регистрацию вашего имени отправителя (альфа-имени)

Имя отправителя SMS – это замена номера телефона, от которого вашим клиентам будут приходить SMS. При получении SMS они увидят не номер телефона, а, например, название вашей компании, что позволит им сразу понять от кого пришло сообщение.

Доступны для использования только те ваши имена отправителей, которые имеют статус модерации «Промодерирован» и статус регистрации у операторов «Зарегистрирован».

Посмотреть список доступных вам имен отправителя можно в личном кабинете SMS-ассистента в разделе «Мои настройки» → вкладка «Отправитель». Здесь вы также увидите их статус модерации и регистрации:

!

На демо-доступе или до момента регистрации вашего имени отправителя у операторов (на полном доступе), вы можете отправлять только 20 тестовых SMS в день с тестовым именем отправителя TEST-assist. При этом в текст SMS будет автоматически добавлена фраза TEST SMS

Подключение формы

  1. Сохраните модуль для подтверждения номера телефона

Скачайте архив с модулем к себе на компьютер. Распакуйте его.

  1. Впишите свои данные

  1. Перейдите в папку lib/sms-assistent.by/conf/
  2. Откройте файл sms_assistent.conf.php в программе “Блокнот”:

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

Параметр

Исходный текст

На что нужно заменить

API_USERNAME

Имя пользователя*

На ваш логин, для доступа в Личный кабинет. Регистр букв (большие/маленькие) имеет значение.

API_PASSWORD

Пароль к API*

На ваш пароль, для API, который вы получаете при в момент подключения API (см. “Перед тем как начать. 2 Подключите API в Личном кабинете”) . Регистр букв (большие/маленькие) имеет значение.

API_SENDER

ОТПРАВИТЕЛЬ*

На ваше имя отправителя в SMS (подпись SMS), которое доступно для отправки SMS. Регистр букв (большие/маленькие) имеет значение.

SMS_TEXT

по умолчанию не указан

Если ничего не заполнять, то будет отправлен только код, состоящий из 5-ти цифр. Как дополнительно к коду вставить свой текст SMS смотрите здесь.

* обязательные параметры

  1. Вставьте форму на сайт

  1. На сервере, на котором расположен ваш сайт, или в административной панели сайта, откройте папку, в которой содержится файл со страницей сайта, на которую нужно вставить форму с кодом подтверждения.
  2. Скопируйте в эту папку из папки с модулем, которая расположена на вашем компьютере, папку lib.
  3. На компьютере в папке с модулем откройте файл index.html в программе “Блокнот” и скопируйте всё его содержимое.
  4. На сервере, на котором расположен сайт, или в административной панели сайта откройте для редактирования файл со страницей сайта, на которую нужно вставить форму с кодом подтверждения.
  5. Вставьте в нужное вам место скопированное содержимое файла index.html и сохраните этот файл.
  6. Откройте в браузере страницу сайта, на которую вы вставляли форму, обновите её (F5 на клавиатуре) – форма должна появиться на экране.
  7. Проверьте работу формы:
  • введите свой номер телефона, нажмите [Выслать код]. На экране должно отобразиться сообщение: Сообщение успешно отправлено
  • проверьте телефон – на него должна прийти SMS. Введите полученный код в поле “Код из SMS” и нажмите [Подтвердить]. Должно появиться сообщение Номер телефона ХХХХХХХХХХХ успешно подтвержден.

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

  1. Если всё работает, осталось только добавить собственные действия после подтверждения номера телефона. Это делается на вашей стороне.

Добавление собственных последующих действий после успешного/неуспешного подтверждения номера телефона

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

Вам необходимо на сервере, на котором расположен сайт, в папке lib:

  • Вариант 1. Открыть файл sms-assistent.by-1.1.js (полный путь к файлу lib/sms-assistent.by/js/sms-assistent.by-1.1.js) и найти в нём места для вставки своего кода. Они помечены комментариями:

// Проверка успешно пройдена, место для вставки кода

// Проверка не пройдена, место для вставки кода

И вставить javascript, jquery запрос.

  • Вариант 2. Открыть файл sms-assistent.by.back.php (полный путь к файлу lib/sms-assistent.by/sms-assistent.by.back.php) и после строчек:

$request_data[‘tel’] = $result[‘result’];

$request_data[‘message’] = ‘Номер телефона ‘.$result[‘result’].’ успешно подтвержден.’;

$request_data[‘check_result’] = 1;

вставить свой php-код, который необходимо выполнить, когда номер телефона успешно подтвержден.

Вывод результатов действий пользователя

После нажатия кнопки [Выслать код]

В зависимости от результата, пользователю на экране отображается следующая информация:

Отображаемая информация

Описание и код ошибки

Некорректное значение номера получателя

Появляется при вводе некорректного номера телефона. Ошибка “-4”.

Сообщение успешно отправлено

Номер телефона введён корректно, SMS отправлено на введённый номер телефона

Невозможно отправить SMS, обратитесь к владельцу интернет-ресурса

Выводится при всех остальных неописанных здесь ошибках на стороне владельца интернет-ресурса.

Превышено разрешенное количество проверок по одному номеру телефона

Проверяется количество отправок SMS на один и тот же номер телефона в пределах одного интернет-ресурса, на котором установлена форма. Лимит установлен на 5 SMS в течение 60 минут. Ошибка “-21”.

После нажатия кнопки [Подтвердить]

В зависимости от результата, пользователю на экране отображается следующая информация:

Отображаемая информация

Описание и код ошибки

Введённый код неверен. Введите правильный код или отправьте еще одно SMS и повторите ввод кода.

При несовпадении отправленного SMS-кой кода с введённым или по истечении установленного лимита времени. Ошибка “-23”.

Номер телефона ХХХХХХХХХХХ успешно подтвержден.

При совпадении введённого и отправленного кода в SMS.

Невозможно выполнить подтверждение, обратитесь к владельцу интернет-ресурса

Выводится при всех остальных неописанных здесь ошибках на стороне владельца интернет-ресурса.

Информация для тех, кто хочет изменить форму под себя

  1. Описание содержимого архива

Архив содержит следующие файлы:

  1. index.html – основной файл, в котором расположен HTML-код формы для подтверждения номера телефона.
  2. lib/sms-assistent.by/conf/sms_assistent.conf.php – настройка подключения к sms-assistent.by.
  3. lib/sms-assistent.by/css/page-1.1.css – общий файл стилей для страницы.
  4. lib/sms-assistent.by/css/sms-assistent.by-1.1.css – файл стилей непосредственно формы подтверждения номера телефона.
  5. lib/sms-assistent.by/js/jquery-1.7.1.min.js – библиотека jQuery.
  6. lib/sms-assistent.by/js/sms-assistent.by-1.1.js – обработчик javascript событий (нажатия на кнопки).
  7. lib/sms-assistent.by/sms_assistent.lib.php – библиотека для интеграции с sms-assistent.by (файл, в котором прописаны функции, необходимые для работы механизма подтверждения номера телефона).
  8. lib/sms-assistent.by/sms-assistent.by.back.php – обработчик php-событий (выполнение действий из библиотеки интеграции с sms-assistent.by п.7 на основании запроса из обработчика javascript п.6).
  1. Описание кода в файле index.html

  1. Строка <script type=»text/javascript» src=»lib/sms-assistent.by/js/jquery-1.7.1.min.js»></script>

Подключение файлов javascript. Jquery для отправки Ajax запроса. Если подключена у вас, то можно удалить.

  1. Строка <script type=»text/javascript» src=»lib/sms-assistent.by/js/sms-assistent.by-1.1.js»></script>

Это вызов обработчика нажатий на кнопки и отправки Ajax запросов. Необходим в том случае, если нужно что-то сделать после подтверждения номера телефона.

  1. Строка <link type=»text/css» rel=»stylesheet» href=»lib/sms-assistent.by/css/page-1.1.css»> 

Подключение общего файла стилей для страницы. Использовать необязательно.

  1. Строка <link type=»text/css» rel=»stylesheet» href=»lib/sms-assistent.by/css/sms-assistent.by-1.1.css»>

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

  1. Код формы подтверждения номера телефона

Фундаментально важный HTML-код, который менять нежелательно, выделен красным.

<form>

<input type=»hidden» name=»check_hash» id=»check_hash» value=»»>

<div class=»smsassistent-formdesc»>Введите номер вашего мобильного телефона, на него будет отправлен SMS-код, который в течение 5 минут необходимо ввести в форму ниже. <br> Количество отправок SMS на один и тот же номер телефона ограничено.</div>

<div class=»smsassistent-messages» id=»check_messages»></div>

<div class=»smsassistent-row»>

<div class=»smsassistent-rowtitle»>Ваш телефон</div>

<div class=»smsassistent-rowvalue»><input type=»text» name=»check_telephone» id=»check_telephone»></div>

<div class=»smsassistent-rowbutton»><input type=»button» name=»but_check_telephone» id=»but_check_telephone» value=»Выслать код«></div>

<div class=»smsassistent-separator»></div>

</div>

<div class=»smsassistent-row»>

<div class=»smsassistent-rowtitle»>Код из SMS</div>

<div class=»smsassistent-rowvalue»><input type=»text» name=»check_code» id=»check_code»></div>

<div class=»smsassistent-rowbutton»><input type=»button» name=»but_check_code» id=»but_check_code» value=»Подтвердить«></div>

<div class=»smsassistent-separator»></div>

<div class=»smsassistent-messages» id=»check_messages»></div>

        </div>

</form>

По умолчанию в SMS отправляется только код, состоящий из 5-ти цифр. Если, помимо кода, вам необходимо добавить свой текст SMS, то сделать вы это можете в файле lib/sms-assistent.by/conf/sms_assistent.conf.php. В этом файле в параметре define(‘SMS_TEXT’, ); между апострофами   нужно вставить свой текст SMS.

Вариант по умолчанию

В параметре define(‘SMS_TEXT’, ); между апострофами   ничего не введено.

В файле:

На телефоне будет SMS, содержащее только код из 5-ти цифр:

Вариант использования вставки только текста (код подтверждения автоматически вставляется в конец текста SMS)

Вы можете добавить свой текст в SMS, и тогда вставка кода подтверждения произойдёт автоматически в конец текста сообщения. Текст сообщения должен быть длиной не более 1 SMS. Поэтому, с учётом автоматической вставки кода (5 символов), вы можете вписать текст длиной 65 символов по-русски или 155 символов латиницей. В параметре define(‘SMS_TEXT’, ); между апострофами введено: Ваш код подтверждения на сайте www.sms-assistent.by:

В файле необходимо вставить:

В этом случае код подтверждения, состоящий из 5-ти цифр, автоматически вставляется в конец текста SMS:

Вариант использования вставки своего текста и кода подтверждения в любое место текста

Вы можете добавить код подтверждения в любое место текста SMS, используя для этого специальную вставку тега {KOD}. Текст сообщения должен быть длиной не более 1 SMS, поэтому вы можете добавить текст длиной 70 символов по-русски или 160 символов латиницей. В примере, в параметре define(‘SMS_TEXT’,’ ‘); между апострофами введено: Ваш код подтверждения {KOD}, введите его в поле “Код из SMS”.

В файле необходимо вставить:

На телефоне в SMS вместо тега {KOD} будет вставлен код подтверждения, состоящий из 5-ти цифр:

  1. Изменение предустановленных лимитов

По умолчанию установлены следующие лимиты:

  • Лимит на отправку SMS одному и тому же абоненту с одной и той же формы (5 SMS в течение 60 минут).
  • Лимит на количество минут, отведённое для ввода кода подтверждения в форму.

Изменить эти лимиты можно в вашем Личном кабинете сервиса SMS-ассистент.[3]

  1. Важные замечания

  1. При изменении расположения файлов CSS

Вам необходимо изменить в коде из файла index.html информацию в следующих строках (указать новый путь к этим файлам):

<link type=»text/css» rel=»stylesheet» href=»lib/sms-assistent.by/css/page-1.1.css»>

<link type=»text/css» rel=»stylesheet» href=»lib/sms-assistent.by/css/sms-assistent.by-1.1.css»>

  1. При изменении расположения файлов js

Вам необходимо изменить в коде из файла index.html информацию в следующих строках (указать новый путь к этим файлам):

<script type=»text/javascript» src=»lib/sms-assistent.by/js/jquery-1.7.1.min.js»></script>

<script type=»text/javascript» src=»lib/sms-assistent.by/js/sms-assistent.by-1.1.js»></script>

  1. Файлы sms-assistent.by.back.php, sms_assistent.lib.php и папку conf (вместе с содержимым) перемещать вместе

В случае переноса файлов, необходимо в 2-х местах в файле sms-assistent.by-1.1.js изменить следующую строку (указать новый путь к этим файлам):

url: ‘lib/sms-assistent.by/sms-assistent.by.back.php’,



www.sms-assistent.by                                                       
support@sms-assistent.by


[1] По умолчанию включена отправка SMS только абонентам Республики Беларусь. При попытке отправки SMS в другие страны, пользователю будет отображаться ошибка “Некорректное значение номера получателя“. Для отправки SMS в другие страны вам необходимо подключить эти страны в вашем личном кабинете SMS-ассистента в разделе “Мои тарифы”.

[2] Реализация самостоятельной регулировки в личном кабинете планируется при следующем обновлении.

[3] Планируется при следующем обновлении.

Данное руководство устарело. Актуальное руководство: Руководство по ASP.NET Core

Последнее обновление: 02.12.2015

ASP.NET MVC 5 поддерживает также подтверждение регистрации по sms. Но чтобы включить данную функциональность в приложении, нам надо связать
наше приложение с сервисом, который будет отправлять sms через специальный API. Одним из таких сервисов является Twilio

Итак, создадим проект и первым делом подключим через NuGet пакет, который позволит взаимодействовать с этим сервисом:

Twilio в ASP.NET MVC 5

Теперь надо зарегистрироваться на самом этом сервисе и получить идентификатор аккаунта ACCOUNT SID, токен AUTH TOKEN и привязанный к приложению номер телефона,
с которого будут отправляться sms.

Значения ACCOUNT SID и AUTH TOKEN можно найти в личном кабинете:

Через пункт меню Numbers можно увидеть номер телефона, привязанный к аккаунту:

Также нам потребуется подключить все те страны, с телефонными кодами которых мы будем взаимодействовать. Это можно сделать в личном кабинете
в меню Geographic Permissions на вкладке Messaging. Здесь нам надо отметить все необходимые страны:

После создания учетной записи в Twilio первым делом подключим этот сервис к себе в приложение. Для этого перейдем в файл IdentityConfig.cs,
который располагается в папке App_Start. В нем уже приготовлен специальный класс для отправки sms, но пока он по сути ничего не делает:

public class SmsService : IIdentityMessageService
{
    public Task SendAsync(IdentityMessage message)
    {
        // Plug in your sms service here to send a text message.
        return Task.FromResult(0);
    }
}

Там же в файле в методе Create происходит установка этого сервиса для менеджера учетных записей: manager.SmsService = new SmsService();

И теперь подключим в начало файла функциональность twilio: using Twilio; и изменим код сервиса следующим образом:

public class SmsService : IIdentityMessageService
{
    public Task SendAsync(IdentityMessage message)
    {
        string AccountSid = "AC60671f39f9c1edd419022c8f0f9efe9e";

        string AuthToken = "f62e1374032b4b2838d07f085b678d15";

        string twilioPhoneNumber = "+13095884640";

        var twilio = new TwilioRestClient(AccountSid, AuthToken);
		twilio.SendMessage(twilioPhoneNumber, message.Destination, message.Body);

        return Task.FromResult(0);
}

Переменная AccountSid будет хранить идентификатор вашего аккаунта ACCOUNT SID, переменная AuthToken
содержит токен AUTH TOKEN, а twilioPhoneNumber — номер телефона, привязанного к вашему аккаунту. В данном случае все эти значения
из моего аккаунта, для вашего аккаунта Twilio они будут отличаться.

Теперь надо создать инфраструктуру для отправки sms и верификации полученных через sms кодов.

Модель пользователя ApplicationUser уже имеет свойство PhoneNumber, которое представляет телефон пользователя, а
также свойство PhoneNumberConfirmed, указывающее, был ли подтвержден номер телефона. Однако напрямую с этими свойствами при подтверждении мы не будем
взаимодействовать, а будем обращаться через специальные методы. Для этого перейдем к контроллеру ManageController. Он уже имеет две пары методов, которые нам понадобятся
для работы. Во-первых, метод AddPhoneNumber, который принимает номер телефона и отправляет на него код:

public ActionResult AddPhoneNumber()
{
    return View();
}

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> AddPhoneNumber(AddPhoneNumberViewModel model)
{
    if (!ModelState.IsValid)
    {
        return View(model);
    }
    var code = await UserManager.GenerateChangePhoneNumberTokenAsync(User.Identity.GetUserId(), model.Number);
    if (UserManager.SmsService != null)
    {
        var message = new IdentityMessage
        {
            Destination = model.Number,
            Body = "Your security code is: " + code
        };
        await UserManager.SmsService.SendAsync(message);
    }
    return RedirectToAction("VerifyPhoneNumber", new { PhoneNumber = model.Number });
}

Во-вторых, это метод VerifyPhoneNumber, который верифицирует код:

public async Task<ActionResult> VerifyPhoneNumber(string phoneNumber)
{
    var code = await UserManager.GenerateChangePhoneNumberTokenAsync(User.Identity.GetUserId(), phoneNumber);
    return phoneNumber == null ? View("Error") : View(new VerifyPhoneNumberViewModel { PhoneNumber = phoneNumber });
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> VerifyPhoneNumber(VerifyPhoneNumberViewModel model)
{
    if (!ModelState.IsValid)
    {
        return View(model);
    }
    var result = await UserManager.ChangePhoneNumberAsync(User.Identity.GetUserId(), model.PhoneNumber, model.Code);
    if (result.Succeeded)
    {
        var user = await UserManager.FindByIdAsync(User.Identity.GetUserId());
        if (user != null)
        {
            await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);
        }
        return RedirectToAction("Index", new { Message = ManageMessageId.AddPhoneSuccess });
    }
    ModelState.AddModelError("", "Failed to verify phone");
    return View(model);
}

Метод AddPhoneNumber в GET-версии возвращает представление, которое предназначено для ввода телефона. А POST-версия метода принимает
введенный номер в виде модели AddPhoneNumberViewModel и на основе этого номера генерирует код:
var code = await UserManager.GenerateChangePhoneNumberTokenAsync(User.Identity.GetUserId(), model.Number);

Затем формируется сообщение: var message = new IdentityMessage { Destination = model.Number, Body = "Your security code is: " + code};.
Это сообщение отправляется await UserManager.SmsService.SendAsync(message);, а фактически передается вышеопределенному классу
SmsService для непосредственной отправки.

После этого пользователь перенаправляется на страницу ввода кода, а на телефон пользователя приходит код. После ввода кода данные обрабатываются post-методом
VerifyPhoneNumber, в котором с помощью вызова var result = await UserManager.ChangePhoneNumberAsync(User.Identity.GetUserId(), model.PhoneNumber, model.Code);
введенный код сравнивается с токеном из бд. Если сравнение прошло успешно, то result.Succeeded возвратит значение true

Для данных методов в файле ManageViewModels.cs уже определены все необходимые модели:

public class AddPhoneNumberViewModel
{
    [Required]
    [Phone]
    [Display(Name = "Phone Number")]
    public string Number { get; set; }
}

public class VerifyPhoneNumberViewModel
{
    [Required]
    [Display(Name = "Code")]
    public string Code { get; set; }

    [Required]
    [Phone]
    [Display(Name = "Phone Number")]
    public string PhoneNumber { get; set; }
}

А в папке Views/Manage уже имеются представления AddPhoneNumber.cshtml и VerufyPhoneNumber.cs.

Запустим приложение, зарегистрируемся и перейдем к добавлению номера по ссылке Manage/AddPhoneNumber:

Номер вводится с плюсиком, например, +79262221133.

После ввода номера мы получим смс на телефон следующего вида:

Введем полученный код:

И после успешной проверки нам отобразится соответствующая страница:

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

Понравилась статья? Поделить с друзьями:
  • Подтверждение номера телефона через госуслуги корпоративного
  • Подтверждение номера телефона на фейсите
  • Подтверждение номера телефона на госуслугах корпоративного мегафона
  • Подтверждение номера телефона на госуслугах билайн
  • Подтверждение номера телефона на айфоне