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

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

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

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

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

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

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

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

    1. В консоли Firebase откройте раздел «Аутентификация» .
    2. На вкладке «Способ входа » включите поставщика услуг «Электронная почта/Пароль» . Обратите внимание, что для использования входа по ссылке на электронную почту необходимо включить вход по электронной почте/паролю.
    3. В этом же разделе включите метод входа по ссылке на электронную почту (вход без пароля) .
    4. Нажмите «Сохранить ».

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

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

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

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

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

    • 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 прекращена; для отправки ссылки для входа теперь используется 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();