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

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

Вход по электронной почте имеет ряд преимуществ:

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

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

  1. Если вы еще этого не сделали, следуйте инструкциям в руководстве по началу работы .

  2. Включите вход по ссылке электронной почты для вашего проекта Firebase.

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

    1. В консоли Firebase откройте раздел Auth .
    2. На вкладке Sign in method включите поставщика Email/Password . Обратите внимание, что для использования входа по ссылке на электронную почту необходимо включить вход по электронной почте/паролю.
    3. В этом же разделе включите метод входа по ссылке на электронную почту (вход без пароля) .
    4. Нажмите «Сохранить» .

Чтобы инициировать процесс аутентификации, предоставьте интерфейс, который предлагает пользователю указать свой адрес электронной почты, а затем вызовите sendSignInLinkToEmail() , чтобы запросить у Firebase отправку ссылки для аутентификации на электронную почту пользователя.

  1. Создайте объект ActionCodeSettings, который предоставляет Firebase инструкции о том, как создать ссылку на электронную почту. Установите следующие поля:

    • url : Глубокая ссылка для встраивания и любое дополнительное состояние, которое должно быть передано. Домен ссылки должен присутствовать в списке авторизованных доменов Firebase Console, который можно найти, перейдя на вкладку Настройки (Аутентификация -> Настройки -> Авторизованные домены). Ссылка перенаправит пользователя на этот URL, если приложение не установлено на его устройстве и приложение не удалось установить.

    • androidPackageName и IOSBundleId : приложения, которые следует использовать при открытии ссылки входа на устройстве Android или iOS. Узнайте больше о том, как настроить Firebase Dynamic Links для открытия ссылок действий электронной почты через мобильные приложения.

    • handleCodeInApp : Установите значение true . Операция входа всегда должна быть завершена в приложении, в отличие от других действий электронной почты вне диапазона (сброс пароля и проверки электронной почты). Это связано с тем, что в конце потока ожидается, что пользователь войдет в систему, а его состояние Auth сохранится в приложении.

    • dynamicLinkDomain : (устарело, используйте linkDomain ) Если для проекта определено несколько пользовательских доменов динамических ссылок, укажите, какой из них использовать, когда ссылка должна открываться с помощью указанного мобильного приложения (например, example.page.link ). В противном случае автоматически выбирается первый домен.

    • linkDomain : необязательный пользовательский домен Firebase Hosting для использования при открытии ссылки с помощью указанного мобильного приложения. Домен должен быть настроен в Firebase Hosting и принадлежать проекту. Это не может быть доменом Hosting по умолчанию ( web.app или firebaseapp.com ). Это заменяет устаревшую настройку dynamicLinkDomain .

    var acs = ActionCodeSettings(
        // URL you want to redirect back to. The domain (www.example.com) for this
        // URL must be whitelisted in the Firebase Console.
        url: 'https://www.example.com/finishSignUp?cartId=1234',
        // This must be true
        handleCodeInApp: true,
        iOSBundleId: 'com.example.ios',
        androidPackageName: 'com.example.android',
        // installIfNotAvailable
        androidInstallApp: true,
        // minimumVersion
        androidMinimumVersion: '12');
    
  2. Спросите у пользователя его адрес электронной почты.

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

    var emailAuth = 'someemail@domain.com';
    FirebaseAuth.instance.sendSignInLinkToEmail(
            email: emailAuth, actionCodeSettings: acs)
        .catchError((onError) => print('Error sending email verification $onError'))
        .then((value) => print('Successfully sent email verification'));
    });
    

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

Чтобы предотвратить использование ссылки для входа в качестве непреднамеренного пользователя или на непреднамеренном устройстве, Firebase Auth требует предоставления адреса электронной почты пользователя при завершении процесса входа. Для успешного входа этот адрес электронной почты должен совпадать с адресом, на который изначально была отправлена ​​ссылка для входа.

Вы можете оптимизировать этот поток для пользователей, которые открывают ссылку для входа на том же устройстве, на котором они запрашивают ссылку, сохранив их адрес электронной почты локально — например, с помощью SharedPreferences — при отправке письма для входа. Затем используйте этот адрес для завершения потока. Не передавайте адрес электронной почты пользователя в параметрах URL перенаправления и не используйте его повторно, так как это может привести к инъекциям сеанса.

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

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

Завершите вход

Firebase Dynamic Links устарела; Firebase Hosting теперь используется для отправки ссылки входа. Следуйте инструкциям по настройке платформы:

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

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

    // Confirm the link is a sign-in with email link.
    if (FirebaseAuth.instance.isSignInWithEmailLink(emailLink)) {
      try {
        // The client SDK will parse the code from the link for you.
        final userCredential = await FirebaseAuth.instance
            .signInWithEmailLink(email: emailAuth, emailLink: emailLink);
    
        // You can access the new user via userCredential.user.
        final emailAddress = userCredential.user?.email;
    
        print('Successfully signed in with email link!');
      } catch (error) {
        print('Error signing in with email link.');
      }
    }
    

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

Разница будет во второй половине операции:

final authCredential = EmailAuthProvider
    .credentialWithLink(email: emailAuth, emailLink: emailLink.toString());
try {
    await FirebaseAuth.instance.currentUser
        ?.linkWithCredential(authCredential);
} catch (error) {
    print("Error linking emailLink credential.");
}

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

final authCredential = EmailAuthProvider
    .credentialWithLink(email: emailAuth, emailLink: emailLink.toString());
try {
    await FirebaseAuth.instance.currentUser
        ?.reauthenticateWithCredential(authCredential);
} catch (error) {
    print("Error reauthenticating credential.");
}

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

Если вы создали свой проект 15 сентября 2023 года или позже, защита перечисления адресов электронной почты включена по умолчанию. Эта функция повышает безопасность учетных записей пользователей вашего проекта, но отключает метод fetchSignInMethodsForEmail() , который мы ранее рекомендовали для реализации потоков с приоритетом идентификатора.

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

Более подробную информацию см. в документации по защите от перечисления адресов электронной почты .

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

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

В своих приложениях вы можете получить основную информацию о профиле пользователя из объекта User . См. Управление пользователями .

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

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

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

await FirebaseAuth.instance.signOut();