Аутентификация в Firebase по номеру телефона с использованием JavaScript

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

Самый простой способ добавить вход по номеру телефона в приложение — использовать FirebaseUI , который включает в себя встроенный виджет входа, реализующий различные способы входа по номеру телефона, а также вход по паролю и федеративный вход. В этом документе описывается, как реализовать процесс входа по номеру телефона с помощью Firebase SDK.

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

Если вы еще этого не сделали, скопируйте фрагмент инициализации из консоли Firebase в свой проект, как описано в разделе Добавление Firebase в ваш проект JavaScript .

Проблемы безопасности

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

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

Включите вход по номеру телефона для вашего проекта Firebase

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

  1. В консоли Firebase откройте раздел «Аутентификация» .
  2. На странице «Способ входа» включите способ входа по номеру телефона .
  3. Необязательно : на странице настроек задайте политику регионов, в которых вы хотите разрешить или запретить отправку SMS-сообщений. Настройка политики региона для SMS поможет защитить ваши приложения от злоупотреблений SMS.
  4. На той же странице, если домен, на котором будет размещено ваше приложение, не указан в разделе «Домены перенаправления OAuth» , добавьте свой домен. Обратите внимание, что localhost не допускается в качестве размещенного домена для телефонной аутентификации.

Настройте верификатор reCAPTCHA

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

Вам не нужно вручную настраивать клиент reCAPTCHA; при использовании объекта RecaptchaVerifier из Firebase SDK Firebase автоматически создает и обрабатывает все необходимые клиентские ключи и секреты.

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

Базовую отрисовку reCAPTCHA можно локализовать в соответствии с предпочтениями пользователя, обновив код языка в экземпляре Auth перед её отрисовкой. Вышеуказанная локализация также будет применена к отправляемому пользователю SMS-сообщению с кодом подтверждения.

Web

import { getAuth } from "firebase/auth";

const auth = getAuth();
auth.languageCode = 'it';
// To apply the default browser preference instead of explicitly setting it.
// auth.useDeviceLanguage();

Web

firebase.auth().languageCode = 'it';
// To apply the default browser preference instead of explicitly setting it.
// firebase.auth().useDeviceLanguage();

Использовать невидимую reCAPTCHA

Чтобы использовать невидимую reCAPTCHA, создайте объект RecaptchaVerifier с параметром size равным invisible , и укажите идентификатор кнопки, которая отправляет форму входа. Например:

Web

import { getAuth, RecaptchaVerifier } from "firebase/auth";

const auth = getAuth();
window.recaptchaVerifier = new RecaptchaVerifier(auth, 'sign-in-button', {
  'size': 'invisible',
  'callback': (response) => {
    // reCAPTCHA solved, allow signInWithPhoneNumber.
    onSignInSubmit();
  }
});

Web

window.recaptchaVerifier = new firebase.auth.RecaptchaVerifier('sign-in-button', {
  'size': 'invisible',
  'callback': (response) => {
    // reCAPTCHA solved, allow signInWithPhoneNumber.
    onSignInSubmit();
  }
});

Используйте виджет reCAPTCHA

Чтобы использовать видимый виджет reCAPTCHA, создайте на странице элемент, содержащий виджет, а затем создайте объект RecaptchaVerifier , указав при этом идентификатор контейнера. Например:

Web

import { getAuth, RecaptchaVerifier } from "firebase/auth";

const auth = getAuth();
window.recaptchaVerifier = new RecaptchaVerifier(auth, 'recaptcha-container', {});

Web

window.recaptchaVerifier = new firebase.auth.RecaptchaVerifier('recaptcha-container');

Необязательно: укажите параметры reCAPTCHA

При желании вы можете задать функции обратного вызова для объекта RecaptchaVerifier , которые будут вызываться, когда пользователь решает reCAPTCHA или срок действия reCAPTCHA истекает до того, как пользователь отправит форму:

Web

import { getAuth, RecaptchaVerifier } from "firebase/auth";

const auth = getAuth();
window.recaptchaVerifier = new RecaptchaVerifier(auth, 'recaptcha-container', {
  'size': 'normal',
  'callback': (response) => {
    // reCAPTCHA solved, allow signInWithPhoneNumber.
    // ...
  },
  'expired-callback': () => {
    // Response expired. Ask user to solve reCAPTCHA again.
    // ...
  }
});

Web

window.recaptchaVerifier = new firebase.auth.RecaptchaVerifier('recaptcha-container', {
  'size': 'normal',
  'callback': (response) => {
    // reCAPTCHA solved, allow signInWithPhoneNumber.
    // ...
  },
  'expired-callback': () => {
    // Response expired. Ask user to solve reCAPTCHA again.
    // ...
  }
});

Необязательно: предварительно визуализируйте reCAPTCHA.

Если вы хотите предварительно отобразить reCAPTCHA перед отправкой запроса на вход, вызовите render :

Web

recaptchaVerifier.render().then((widgetId) => {
  window.recaptchaWidgetId = widgetId;
});

Web

recaptchaVerifier.render().then((widgetId) => {
  window.recaptchaWidgetId = widgetId;
});

После завершения render вы получите идентификатор виджета reCAPTCHA, который можно использовать для совершения вызовов API reCAPTCHA :

Web

const recaptchaResponse = grecaptcha.getResponse(recaptchaWidgetId);

Web

const recaptchaResponse = grecaptcha.getResponse(recaptchaWidgetId);

Отправить проверочный код на телефон пользователя

Чтобы инициировать вход по номеру телефона, предоставьте пользователю интерфейс, предлагающий ему указать свой номер телефона, а затем вызовите signInWithPhoneNumber , чтобы запросить у Firebase отправку кода аутентификации на телефон пользователя по SMS:

  1. Получите номер телефона пользователя.

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

  2. Вызовите signInWithPhoneNumber , передав ему номер телефона пользователя и RecaptchaVerifier который вы создали ранее.

    Web

    import { getAuth, signInWithPhoneNumber } from "firebase/auth";
    
    const phoneNumber = getPhoneNumberFromUserInput();
    const appVerifier = window.recaptchaVerifier;
    
    const auth = getAuth();
    signInWithPhoneNumber(auth, phoneNumber, appVerifier)
        .then((confirmationResult) => {
          // SMS sent. Prompt user to type the code from the message, then sign the
          // user in with confirmationResult.confirm(code).
          window.confirmationResult = confirmationResult;
          // ...
        }).catch((error) => {
          // Error; SMS not sent
          // ...
        });

    Web

    const phoneNumber = getPhoneNumberFromUserInput();
    const appVerifier = window.recaptchaVerifier;
    firebase.auth().signInWithPhoneNumber(phoneNumber, appVerifier)
        .then((confirmationResult) => {
          // SMS sent. Prompt user to type the code from the message, then sign the
          // user in with confirmationResult.confirm(code).
          window.confirmationResult = confirmationResult;
          // ...
        }).catch((error) => {
          // Error; SMS not sent
          // ...
        });
    Если signInWithPhoneNumber приводит к ошибке, сбросьте reCAPTCHA, чтобы пользователь мог повторить попытку:
    grecaptcha.reset(window.recaptchaWidgetId);
    
    // Or, if you haven't stored the widget ID:
    window.recaptchaVerifier.render().then(function(widgetId) {
      grecaptcha.reset(widgetId);
    });

Метод signInWithPhoneNumber отправляет пользователю запрос reCAPTCHA и, если пользователь проходит его, запрашивает у Firebase Authentication отправку SMS-сообщения с кодом подтверждения на телефон пользователя.

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

После успешного вызова signInWithPhoneNumber предложите пользователю ввести код подтверждения, полученный по SMS. Затем авторизуйте пользователя, передав код методу confirm объекта ConfirmationResult , который был передан обработчику выполнения signInWithPhoneNumber (то есть его блоку then ). Например:

Web

const code = getCodeFromUserInput();
confirmationResult.confirm(code).then((result) => {
  // User signed in successfully.
  const user = result.user;
  // ...
}).catch((error) => {
  // User couldn't sign in (bad verification code?)
  // ...
});

Web

const code = getCodeFromUserInput();
confirmationResult.confirm(code).then((result) => {
  // User signed in successfully.
  const user = result.user;
  // ...
}).catch((error) => {
  // User couldn't sign in (bad verification code?)
  // ...
});

Если вызов для confirm прошел успешно, пользователь успешно вошел в систему.

Получить промежуточный объект AuthCredential

Если вам нужно получить объект AuthCredential для учетной записи пользователя, передайте код проверки из результата подтверждения и код проверки в PhoneAuthProvider.credential вместо вызова confirm :

var credential = firebase.auth.PhoneAuthProvider.credential(confirmationResult.verificationId, code);

Затем вы можете войти в систему, используя учетные данные пользователя:

firebase.auth().signInWithCredential(credential);

Тест с вымышленными номерами телефонов

Вы можете настроить вымышленные номера телефонов для разработки через консоль Firebase . Тестирование с вымышленными номерами телефонов даёт следующие преимущества:

  • Протестируйте аутентификацию по номеру телефона, не исчерпывая квоту использования.
  • Проверьте аутентификацию по номеру телефона без отправки реального SMS-сообщения.
  • Проводите последовательные тесты с одним и тем же номером телефона, не подвергаясь ограничениям. Это минимизирует риск отклонения при проверке в App Store, если проверяющий случайно использует один и тот же номер телефона для тестирования.
  • Легкое тестирование в средах разработки без дополнительных усилий, например, возможность разработки в симуляторе iOS или эмуляторе Android без Google Play Services.
  • Пишите интеграционные тесты, не опасаясь проверок безопасности, которые обычно применяются к реальным телефонным номерам в производственной среде.

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

  1. Убедитесь, что вы используете действительно вымышленные номера телефонов, а не существующие. Firebase Authentication не позволяет использовать существующие номера телефонов реальных пользователей в качестве тестовых. Один из вариантов — использовать номера с префиксом 555 в качестве тестовых номеров в США, например: +1 650-555-3434.
  2. Номера телефонов должны быть правильно отформатированы с учётом длины и других ограничений. Они пройдут ту же проверку, что и реальные номера телефонов пользователей.
  3. Вы можете добавить до 10 номеров телефонов для разработки.
  4. Используйте тестовые номера телефонов/коды, которые трудно угадать, и регулярно меняйте их.

Создайте вымышленные номера телефонов и коды подтверждения

  1. В консоли Firebase откройте раздел «Аутентификация» .
  2. На вкладке «Способ входа» включите опцию «Поставщик телефонной связи», если вы этого еще не сделали.
  3. Откройте меню «Телефонные номера для тестирования аккордеона».
  4. Укажите номер телефона, который вы хотите проверить, например: +1 650-555-3434 .
  5. Укажите 6-значный проверочный код для этого конкретного номера, например: 654321 .
  6. Добавьте номер. При необходимости вы можете удалить номер телефона и его код, наведя курсор на соответствующую строку и нажав на значок корзины.

Ручное тестирование

Вы можете сразу начать использовать вымышленный номер телефона в своём приложении. Это позволит проводить ручное тестирование на этапах разработки, не сталкиваясь с проблемами квот или ограничениями. Вы также можете тестировать приложение непосредственно в симуляторе iOS или эмуляторе Android без установленных сервисов Google Play.

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

После завершения входа в систему создаётся пользователь Firebase с этим номером телефона. Этот пользователь обладает теми же характеристиками и свойствами, что и пользователь с реальным номером телефона, и может получать доступ к Realtime Database / Cloud Firestore и другим сервисам таким же образом. Идентификационный токен, созданный в ходе этого процесса, имеет ту же подпись, что и пользователь с реальным номером телефона.

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

Интеграционное тестирование

Помимо ручного тестирования, Firebase Authentication предоставляет API, помогающие писать интеграционные тесты для проверки аутентификации по телефону. Эти API отключают верификацию приложений, отключая требование reCAPTCHA в веб-версии и скрытых push-уведомлениях в iOS. Это делает возможным и упрощает автоматическое тестирование в этих процессах. Кроме того, они помогают тестировать процессы мгновенной верификации на Android.

В веб-версии установите для appVerificationDisabledForTesting значение true перед рендерингом firebase.auth.RecaptchaVerifier . Это автоматически обработает reCAPTCHA, позволяя вам передавать номер телефона без необходимости вручную её решать. Обратите внимание, что даже если reCAPTCHA отключена, использование невымышленного номера телефона всё равно не приведёт к завершению входа. С этим API можно использовать только вымышленные номера телефонов.

// Turn off phone auth app verification.
firebase.auth().settings.appVerificationDisabledForTesting = true;

var phoneNumber = "+16505554567";
var testVerificationCode = "123456";

// This will render a fake reCAPTCHA as appVerificationDisabledForTesting is true.
// This will resolve after rendering without app verification.
var appVerifier = new firebase.auth.RecaptchaVerifier('recaptcha-container');
// signInWithPhoneNumber will call appVerifier.verify() which will resolve with a fake
// reCAPTCHA response.
firebase.auth().signInWithPhoneNumber(phoneNumber, appVerifier)
    .then(function (confirmationResult) {
      // confirmationResult can resolve with the fictional testVerificationCode above.
      return confirmationResult.confirm(testVerificationCode)
    }).catch(function (error) {
      // Error; SMS not sent
      // ...
    });

Видимые и невидимые фиктивные верификаторы приложений reCAPTCHA ведут себя по-разному, если отключена проверка приложений:

  • Видимая reCAPTCHA : При рендеринге видимой reCAPTCHA через appVerifier.render() она автоматически разрешается с задержкой в ​​доли секунды. Это эквивалентно нажатию пользователем кнопки reCAPTCHA сразу после рендеринга. Ответ reCAPTCHA истечёт через некоторое время, а затем автоматически разрешится снова.
  • Невидимая reCAPTCHA : Невидимая reCAPTCHA не разрешается автоматически при рендеринге, а вместо этого делает это при вызове appVerifier.verify() или при нажатии на якорь кнопки reCAPTCHA с задержкой в ​​доли секунды. Аналогично, ответ истекает через некоторое время и автоматически разрешается только после вызова appVerifier.verify() или при повторном нажатии на якорь кнопки reCAPTCHA.

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

Следующие шаги

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

  • В ваших приложениях рекомендуемый способ узнать статус аутентификации пользователя — установить наблюдателя для объекта Auth . После этого вы сможете получить основную информацию о профиле пользователя из объекта User . См. раздел Управление пользователями .

  • В правилах безопасности Firebase Realtime Database и Cloud Storage вы можете получить уникальный идентификатор вошедшего в систему пользователя из переменной auth и использовать его для управления данными, к которым пользователь может получить доступ.

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

Чтобы выйти из системы пользователя, вызовите signOut :

Web

import { getAuth, signOut } from "firebase/auth";

const auth = getAuth();
signOut(auth).then(() => {
  // Sign-out successful.
}).catch((error) => {
  // An error happened.
});

Web

firebase.auth().signOut().then(() => {
  // Sign-out successful.
}).catch((error) => {
  // An error happened.
});