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

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

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

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

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

Вопросы безопасности

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

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

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

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

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

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

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

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

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

Встроенную reCAPTCHA можно локализовать в соответствии с предпочтениями пользователя, обновив языковой код в экземпляре Auth перед отображением reCAPTCHA. Указанная локализация также будет применяться к 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 , и укажите ID кнопки, которая отправляет вашу форму входа. Например:

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.
  • Пишите интеграционные тесты, не сталкиваясь с препятствиями в виде проверок безопасности, обычно применяемых к реальным телефонным номерам в производственной среде.

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

  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.
});