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

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

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

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

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

Настройте свой Android-проект

  1. Если вы еще этого не сделали, добавьте Firebase в свой Android-проект .

  2. В файле Gradle вашего модуля (уровня приложения) (обычно <project>/<app-module>/build.gradle.kts или <project>/<app-module>/build.gradle ) добавьте зависимость для библиотеки Firebase Authentication для Android. Мы рекомендуем использовать Firebase Android BoM для управления версиями библиотеки.

    Кроме того, в рамках настройки Firebase Authentication вам необходимо добавить в свое приложение SDK сервисов Google Play.

    dependencies {
        // Import the BoM for the Firebase platform
        implementation(platform("com.google.firebase:firebase-bom:34.0.0"))
    
        // Add the dependency for the Firebase Authentication library
        // When using the BoM, you don't specify versions in Firebase library dependencies
        implementation("com.google.firebase:firebase-auth")
    // Also add the dependency for the Google Play services library and specify its version implementation("com.google.android.gms:play-services-auth:21.3.0")
    }

    Используя Firebase Android BoM , ваше приложение всегда будет использовать совместимые версии библиотек Firebase Android.

    (Альтернатива) Добавьте зависимости библиотеки Firebase без использования BoM

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

    Обратите внимание: если вы используете в своем приложении несколько библиотек Firebase, мы настоятельно рекомендуем использовать BoM для управления версиями библиотек, что гарантирует совместимость всех версий.

    dependencies {
        // Add the dependency for the Firebase Authentication library
        // When NOT using the BoM, you must specify versions in Firebase library dependencies
        implementation("com.google.firebase:firebase-auth:24.0.0")
    // Also add the dependency for the Google Play services library and specify its version implementation("com.google.android.gms:play-services-auth:21.3.0")
    }

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

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

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

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

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

    • url : Глубокая ссылка для встраивания и любые дополнительные данные о состоянии, которые будут переданы. Домен ссылки должен быть внесён в белый список авторизованных доменов консоли Firebase, который можно найти на вкладке «Способ входа» (Аутентификация -> Способ входа). Ссылка перенаправит пользователя на этот URL, если приложение не установлено на его устройстве и установить его не удалось.
    • androidPackageName и iOSBundleId : помогают Firebase Authentication определить, следует ли создавать веб-ссылку или мобильную ссылку, открываемую на устройстве Android или Apple.
    • handleCodeInApp : Значение true. Операция входа всегда должна выполняться в приложении, в отличие от других действий с электронной почтой (сброс пароля и проверка электронной почты). Это связано с тем, что в конце процесса пользователь должен быть уже вошел в систему, а его состояние авторизации сохраняется в приложении.
    • linkDomain : Если для проекта определены пользовательские домены ссылок Hosting , укажите, какой из них будет использоваться при открытии ссылки в указанном мобильном приложении. В противном случае автоматически выбирается домен по умолчанию (например, PROJECT_ID .firebaseapp.com ).
    • dynamicLinkDomain : устарело. Не указывайте этот параметр.

    Kotlin

    val actionCodeSettings = 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
        setIOSBundleId("com.example.ios")
        setAndroidPackageName(
            "com.example.android",
            true, // installIfNotAvailable
            "12", // minimumVersion
        )
    }

    Java

    ActionCodeSettings actionCodeSettings =
            ActionCodeSettings.newBuilder()
                    // URL you want to redirect back to. The domain (www.example.com) for this
                    // URL must be whitelisted in the Firebase Console.
                    .setUrl("https://www.example.com/finishSignUp?cartId=1234")
                    // This must be true
                    .setHandleCodeInApp(true)
                    .setIOSBundleId("com.example.ios")
                    .setAndroidPackageName(
                            "com.example.android",
                            true, /* installIfNotAvailable */
                            "12"    /* minimumVersion */)
                    .build();

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

  2. Спросите у пользователя его адрес электронной почты.

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

    Kotlin

    Firebase.auth.sendSignInLinkToEmail(email, actionCodeSettings)
        .addOnCompleteListener { task ->
            if (task.isSuccessful) {
                Log.d(TAG, "Email sent.")
            }
        }

    Java

    FirebaseAuth auth = FirebaseAuth.getInstance();
    auth.sendSignInLinkToEmail(email, actionCodeSettings)
            .addOnCompleteListener(new OnCompleteListener<Void>() {
                @Override
                public void onComplete(@NonNull Task<Void> task) {
                    if (task.isSuccessful()) {
                        Log.d(TAG, "Email sent.");
                    }
                }
            });

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

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

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

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

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

Завершение входа в приложение Android

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

Настроить Firebase Hosting

Firebase Authentication использует домены Firebase Hosting при создании и отправке ссылки, предназначенной для открытия в мобильном приложении. Домен Firebase Hosting по умолчанию уже настроен для вас.

  1. Настройте домены Firebase Hosting :

    В консоли Firebase откройте раздел Хостинг .

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

      Это значение понадобится вам при настройке приложения для перехвата входящей ссылки.

    • Если вы хотите использовать пользовательский домен для ссылки электронной почты, вы можете зарегистрировать его в Firebase Hosting и использовать его в качестве домена ссылки.

  2. Настройка Android-приложений:

    Для обработки этих ссылок из вашего Android-приложения необходимо указать имя пакета приложения в настройках проекта консоли Firebase . Кроме того, необходимо предоставить SHA-1 и SHA-256 сертификата приложения.

    Если вы хотите, чтобы эти ссылки перенаправляли на определённое действие, вам потребуется настроить фильтр намерений в файле AndroidManifest.xml . Фильтр намерений должен отлавливать ссылки электронной почты вашего домена. В файле AndroidManifest.xml :

    <intent-filter android:autoVerify="true">
      <action android:name="android.intent.action.VIEW" />
      <category android:name="android.intent.category.BROWSABLE" />
      <category android:name="android.intent.category.DEFAULT" />
      <data
        android:scheme="https"
        android:host="<PROJECT_ID>.firebaseapp.com or your custom domain"
        android:pathPrefix="/__/auth/links" />
    </intent-filter>
    

    Когда пользователи открывают ссылку хостинга с путем /__/auth/links и указанной вами схемой и хостом, ваше приложение начинает действие с этим фильтром намерений для обработки ссылки .

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

Kotlin

val auth = Firebase.auth
val intent = intent
val emailLink = intent.data.toString()

// Confirm the link is a sign-in with email link.
if (auth.isSignInWithEmailLink(emailLink)) {
    // Retrieve this from wherever you stored it
    val email = "someemail@domain.com"

    // The client SDK will parse the code from the link for you.
    auth.signInWithEmailLink(email, emailLink)
        .addOnCompleteListener { task ->
            if (task.isSuccessful) {
                Log.d(TAG, "Successfully signed in with email link!")
                val result = task.result
                // You can access the new user via result.getUser()
                // Additional user info profile *not* available via:
                // result.getAdditionalUserInfo().getProfile() == null
                // You can check if the user is new or existing:
                // result.getAdditionalUserInfo().isNewUser()
            } else {
                Log.e(TAG, "Error signing in with email link", task.exception)
            }
        }
}

Java

FirebaseAuth auth = FirebaseAuth.getInstance();
Intent intent = getIntent();
String emailLink = intent.getData().toString();

// Confirm the link is a sign-in with email link.
if (auth.isSignInWithEmailLink(emailLink)) {
    // Retrieve this from wherever you stored it
    String email = "someemail@domain.com";

    // The client SDK will parse the code from the link for you.
    auth.signInWithEmailLink(email, emailLink)
            .addOnCompleteListener(new OnCompleteListener<AuthResult>() {
                @Override
                public void onComplete(@NonNull Task<AuthResult> task) {
                    if (task.isSuccessful()) {
                        Log.d(TAG, "Successfully signed in with email link!");
                        AuthResult result = task.getResult();
                        // You can access the new user via result.getUser()
                        // Additional user info profile *not* available via:
                        // result.getAdditionalUserInfo().getProfile() == null
                        // You can check if the user is new or existing:
                        // result.getAdditionalUserInfo().isNewUser()
                    } else {
                        Log.e(TAG, "Error signing in with email link", task.getException());
                    }
                }
            });
}

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

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

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

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

Kotlin

// Construct the email link credential from the current URL.
val credential = EmailAuthProvider.getCredentialWithLink(email, emailLink)

// Link the credential to the current user.
Firebase.auth.currentUser!!.linkWithCredential(credential)
    .addOnCompleteListener { task ->
        if (task.isSuccessful) {
            Log.d(TAG, "Successfully linked emailLink credential!")
            val result = task.result
            // You can access the new user via result.getUser()
            // Additional user info profile *not* available via:
            // result.getAdditionalUserInfo().getProfile() == null
            // You can check if the user is new or existing:
            // result.getAdditionalUserInfo().isNewUser()
        } else {
            Log.e(TAG, "Error linking emailLink credential", task.exception)
        }
    }

Java

// Construct the email link credential from the current URL.
AuthCredential credential =
        EmailAuthProvider.getCredentialWithLink(email, emailLink);

// Link the credential to the current user.
auth.getCurrentUser().linkWithCredential(credential)
        .addOnCompleteListener(new OnCompleteListener<AuthResult>() {
            @Override
            public void onComplete(@NonNull Task<AuthResult> task) {
                if (task.isSuccessful()) {
                    Log.d(TAG, "Successfully linked emailLink credential!");
                    AuthResult result = task.getResult();
                    // You can access the new user via result.getUser()
                    // Additional user info profile *not* available via:
                    // result.getAdditionalUserInfo().getProfile() == null
                    // You can check if the user is new or existing:
                    // result.getAdditionalUserInfo().isNewUser()
                } else {
                    Log.e(TAG, "Error linking emailLink credential", task.getException());
                }
            }
        });

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

Kotlin

// Construct the email link credential from the current URL.
val credential = EmailAuthProvider.getCredentialWithLink(email, emailLink)

// Re-authenticate the user with this credential.
Firebase.auth.currentUser!!.reauthenticateAndRetrieveData(credential)
    .addOnCompleteListener { task ->
        if (task.isSuccessful) {
            // User is now successfully reauthenticated
        } else {
            Log.e(TAG, "Error reauthenticating", task.exception)
        }
    }

Java

// Construct the email link credential from the current URL.
AuthCredential credential =
        EmailAuthProvider.getCredentialWithLink(email, emailLink);

// Re-authenticate the user with this credential.
auth.getCurrentUser().reauthenticateAndRetrieveData(credential)
        .addOnCompleteListener(new OnCompleteListener<AuthResult>() {
            @Override
            public void onComplete(@NonNull Task<AuthResult> task) {
                if (task.isSuccessful()) {
                    // User is now successfully reauthenticated
                } else {
                    Log.e(TAG, "Error reauthenticating", task.getException());
                }
            }
        });

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

Ранее для аутентификации по ссылкам электронной почты использовался Firebase Dynamic Links , который будет закрыт 25 августа 2025 года .

Мы опубликовали альтернативное решение в Firebase Authentication Android SDK v23.2.0+ и Firebase BoM v33.9.0+.

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

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

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

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

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

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

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

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

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

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

Kotlin

Firebase.auth.signOut()

Java

FirebaseAuth.getInstance().signOut();