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

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

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

Прежде чем вы начнете

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

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

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

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

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

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

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

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

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

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

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

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

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

Web modular API

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 namespaced API

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

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

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

Web modular API

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 namespaced API

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

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

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

Web modular API

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

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

Web namespaced API

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

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

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

Web modular API

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 namespaced API

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 modular API

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

Web namespaced API

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

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

Web modular API

const recaptchaResponse = grecaptcha.getResponse(recaptchaWidgetId);

Web namespaced API

const recaptchaResponse = grecaptcha.getResponse(recaptchaWidgetId);

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

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

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

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

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

    Web modular API

    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 namespaced API

    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 для отправки SMS-сообщения с кодом подтверждения на телефон пользователя.

Войдите в систему с кодом подтверждения

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

Web modular API

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 namespaced API

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-сообщения.
  • Выполняйте последовательные тесты с одним и тем же номером телефона без ограничения скорости. Это сводит к минимуму риск отклонения во время процесса проверки в магазине приложений, если рецензент использует один и тот же номер телефона для тестирования.
  • Легко тестируйте в средах разработки без каких-либо дополнительных усилий, таких как возможность разработки в симуляторе 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 с этим номером телефона. Пользователь имеет то же поведение и свойства, что и пользователь с реальным номером телефона, и может таким же образом получать доступ к базе данных реального времени/облаку Firestore и другим службам. Токен ID, отчеканенный в ходе этого процесса, имеет ту же подпись, что и реальный пользователь номера телефона.

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

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

В дополнение к ручному тестированию 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 и облачного хранилища вы можете получить уникальный идентификатор пользователя, вошедшего в систему, из переменной auth и использовать его для управления тем, к каким данным пользователь может получить доступ.

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

Чтобы выйти из системы, вызовите signOut :

Web modular API

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

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

Web namespaced API

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