Uwierzytelnianie w Firebase za pomocą linku e-mail na Androidzie

Użyj usługi Uwierzytelnianie Firebase, aby zalogować użytkownika. Wyślij mu e-maila z linkiem, który umożliwi mu zalogowanie się. W ramach tego procesu weryfikowany jest też adres e-mail użytkownika.

Logowanie się za pomocą adresu e-mail ma wiele zalet:

  • Rejestracja i logowanie bez zbędnych formalności.
  • mniejsze ryzyko ponownego użycia hasła w różnych aplikacjach, co może obniżyć bezpieczeństwo nawet dobrze dobranych haseł;
  • Umożliwia uwierzytelnianie użytkownika i weryfikowanie, czy jest on prawowitym właścicielem adresu e-mail.
  • Aby się zalogować, użytkownik potrzebuje tylko dostępu do konta e-mail. Nie musisz być właścicielem numeru telefonu ani konta w mediach społecznościowych.
  • Użytkownik może logować się bezpiecznie bez konieczności podawania (lub zapamiętywania) hasła, co może być uciążliwe na urządzeniu mobilnym.
  • Istniejący użytkownik, który wcześniej logował się przy użyciu identyfikatora e-mail (hasła lub federacji), może uzyskać możliwość logowania się tylko za pomocą adresu e-mail. Na przykład użytkownik, który zapomniał hasło, może się zalogować bez konieczności jego resetowania.

Zanim zaczniesz

Konfigurowanie projektu na Androida

  1. Jeśli jeszcze tego nie zrobiono, dodaj Firebase do projektu na Androida.

  2. pliku Gradle modułu (na poziomie aplikacji) (zwykle <project>/<app-module>/build.gradle.kts lub <project>/<app-module>/build.gradle) dodaj zależność z biblioteką Firebase Authentication na Androida. Zalecamy używanie Firebase Android BoM do kontrolowania wersji biblioteki.

    W ramach konfigurowania Firebase Authentication musisz też dodać do aplikacji pakiet SDK usług Google Play.

    dependencies {
        // Import the BoM for the Firebase platform
        implementation(platform("com.google.firebase:firebase-bom:33.7.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")
    }

    Gdy korzystasz z Firebase Android BoM, aplikacja zawsze używa zgodnych wersji bibliotek Firebase na Androida.

    (Alternatywnie)  Dodaj zależności biblioteki Firebase bez używania pakietu BoM

    Jeśli zdecydujesz się nie używać Firebase BoM, musisz podać każdą wersję biblioteki Firebase w jej wierszu zależności.

    Jeśli w aplikacji używasz kilku bibliotek Firebase, zdecydowanie zalecamy korzystanie z BoM do zarządzania wersjami bibliotek. Dzięki temu wszystkie wersje będą ze sobą zgodne.

    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:23.1.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")
    }
    Szukasz modułu biblioteki dla Kotlina? Od października 2023 r. (Firebase BoM 32.5.0) deweloperzy Kotlina i Java mogą korzystać z głównego modułu biblioteki (szczegółowe informacje znajdziesz w często zadawanych pytaniach dotyczących tej inicjatywy).

Aby umożliwić użytkownikom logowanie się za pomocą linku e-mail, musisz najpierw włączyć w projekcie Firebase dostawcę e-maili i metodę logowania za pomocą linku e-mail:

  1. W konsoli Firebase otwórz sekcję Autoryzacja.
  2. Na karcie Metoda logowania włącz dostawcę E-mail/hasło. Pamiętaj, że aby korzystać z logowania za pomocą linku w e-mailu, musisz włączyć logowanie za pomocą adresu e-mail i hasła.
  3. W tej samej sekcji włącz metodę logowania Link w e-mailu (logowanie bez hasła).
  4. Kliknij Zapisz.

Aby zainicjować proces uwierzytelniania, wyświetl użytkownikowi interfejs, który poprosi go o podanie adresu e-mail, a następnie wywołaj funkcję sendSignInLinkToEmail, aby poprosić Firebase o wysłanie linku uwierzytelniania na adres e-mail użytkownika.

  1. Utwórz obiekt ActionCodeSettings, który zawiera instrukcje dla Firebase dotyczące tworzenia linku e-mail. Ustaw wartości w tych polach:

    • url: precyzyjny link do osadzenia i dodatkowe stany, które mają być przekazywane. Domena linku musi znajdować się na liście autoryzowanych domen w konsoli Firebase (karta Metoda logowania -> Metoda logowania). Jeśli aplikacja nie jest zainstalowana na urządzeniu użytkownika i nie udało się jej zainstalować, link przekieruje użytkownika na ten adres URL.
    • androidPackageNameIOSBundleId: aplikacje, których należy używać po otwarciu linku do logowania na urządzeniu z Androidem lub Apple. Dowiedz się więcej o konfigurowaniu linków dynamicznych Firebase, aby otwierać linki akcji e-maila w aplikacjach mobilnych.
    • handleCodeInApp: ustaw na wartość true. W przeciwieństwie do innych działań wykonywanych poza aplikacją (takich jak resetowanie hasła czy weryfikacja adresu e-mail) operacja logowania musi być zawsze wykonywana w aplikacji. Dzieje się tak, ponieważ na końcu procesu użytkownik powinien być zalogowany, a stan autoryzacji powinien być zachowany w aplikacji.
    • dynamicLinkDomain: jeśli w projekcie zdefiniowano wiele niestandardowych domen linków dynamicznych, określ, której z nich chcesz używać, gdy link ma być otwierany w określonej aplikacji mobilnej (np. example.page.link). W przeciwnym razie pierwsza domena zostanie wybrana automatycznie.

    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();

    Więcej informacji o ustawieniu ActionCodeSettings znajdziesz w sekcji Przekazywanie stanu w działaniach e-mail.

  2. Poproś użytkownika o adres e-mail.

  3. Wyślij link uwierzytelniania na adres e-mail użytkownika i zapisz ten adres na wypadek, gdyby użytkownik zalogował się przez e-maila na tym samym urządzeniu.

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

Potencjalne problemy z bezpieczeństwem

Aby zapobiec używaniu linku logowania przez nieuprawnionego użytkownika lub na nieuprawnionym urządzeniu, usługa Firebase Auth wymaga podania adresu e-mail użytkownika podczas procesu logowania. Aby zalogować się na konto, musisz podać adres e-mail, na który został wysłany link do logowania.

Możesz uprościć ten proces w przypadku użytkowników, którzy otwierają link logowania na tym samym urządzeniu, na którym wysłali prośbę o link, przechowując ich adresy e-mail lokalnie (np. za pomocą SharedPreferences) podczas wysyłania e-maila z linkiem. Następnie użyj tego adresu, aby dokończyć proces. Nie przekazuj adresu e-mail użytkownika w parametrach adresu URL przekierowania ani nie używaj go ponownie, ponieważ może to umożliwić wstrzyknięcie sesji.

Po zakończeniu logowania wszystkie wcześniejsze niesprawdzone mechanizmy logowania zostaną usunięte z konta użytkownika, a istniejące sesje zostaną unieważnione. Jeśli na przykład ktoś wcześniej utworzył niezweryfikowane konto z tym samym adresem e-mail i tym samym hasłem, hasło użytkownika zostanie usunięte, aby uniemożliwić osobie podszywającej się pod właściciela konta, która utworzyła to niezweryfikowane konto, ponowne zalogowanie się za pomocą tego niezweryfikowanego adresu e-mail i hasła.

Pamiętaj też, aby w produkcji używać adresu URL HTTPS, aby uniknąć przechwycenia linku przez serwery pośredniczące.

Logowanie się w aplikacji na Androida

Usługa Uwierzytelnianie Firebase korzysta z Linków dynamicznych Firebase, aby wysyłać linki e-maili na urządzenie mobilne. Aby umożliwić logowanie się za pomocą aplikacji mobilnej, musisz skonfigurować aplikację tak, aby wykrywała przychodzące linki aplikacji, analizowała precyzyjne linki i dokonywała logowania.

Firebase Auth używa linków dynamicznych Firebase podczas wysyłania linku, który ma być otwierany w aplikacji mobilnej. Aby korzystać z tej funkcji, musisz skonfigurować Linki dynamiczne w konsoli Firebase.

  1. Włączanie Linków dynamicznych Firebase:

    1. W konsoli Firebase otwórz sekcję Dynamic Links.
    2. Jeśli nie zaakceptowałeś(-aś) jeszcze warunków Dynamic Links i nie utworzyłeś(-aś) domeny Dynamic Links, zrób to teraz.

      Jeśli domena Dynamic Links została już utworzona, zanotuj ją. Domena Dynamic Linkszazwyczaj wygląda tak:

      example.page.link

      Będzie ona potrzebna do skonfigurowania aplikacji na Apple lub Androida w celu przechwytywania przychodzącego linku.

  2. Konfigurowanie aplikacji na Androida:

    1. Aby obsługiwać te linki w aplikacji na Androida, musisz podać nazwę pakietu Androida w ustawieniach projektu w Konsoli Firebase. Dodatkowo musisz podać hasz SHA-1 i SHA-256 certyfikatu aplikacji.
    2. Po dodaniu domeny linku dynamicznego i upewnieniu się, że aplikacja na Androida jest prawidłowo skonfigurowana, link dynamiczny przekieruje do Twojej aplikacji, zaczynając od aktywności w menu.
    3. Jeśli chcesz, aby link dynamiczny przekierowywał do określonej czynności, musisz skonfigurować filtr intencji w pliku AndroidManifest.xml. Możesz to zrobić, podając domenę linku dynamicznego lub przetwarzacz działania e-mail w filtrze intencji. Domyślnie moduł obsługi działania e-maila jest hostowany w domenie, takiej jak w tym przykładzie:
      PROJECT_ID.firebaseapp.com/
    4. Zastrzeżenia:
      1. Nie podawaj w filtrze intencji adresu URL ustawionego w ustawieniach actionCode.
      2. Podczas tworzenia domeny linków dynamicznych możesz też utworzyć link do skróconego adresu URL. Ten krótki adres URL nie zostanie przekazany. Nie konfiguruj filtra intencji, aby wychwytywał go za pomocą atrybutu android:pathPrefix. Oznacza to, że nie będziesz w stanie wychwycić różnych linków dynamicznych w różnych częściach aplikacji. Możesz jednak sprawdzić parametr zapytania mode w linku, aby dowiedzieć się, jakiej operacji ma zostać wykonana, lub użyć metod pakietu SDK, takich jak isSignInWithEmailLink, aby sprawdzić, czy link, który otrzymała Twoja aplikacja, działa zgodnie z Twoimi oczekiwaniami.
    5. Więcej informacji o otrzymywaniu linków dynamicznych znajdziesz w instrukcjach odbierania linków dynamicznych na Androida.

Gdy otrzymasz link w sposób opisany powyżej, sprawdź, czy jest on przeznaczony do uwierzytelniania za pomocą linku e-mail, i zaloguj się.

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

Więcej informacji o logowaniu się za pomocą linku e-mail w aplikacji Apple znajdziesz w przewodniku po platformach Apple.

Aby dowiedzieć się, jak obsługiwać logowanie za pomocą linku e-maila w aplikacji internetowej, zapoznaj się z przewodnikiem po aplikacjach internetowych.

Możesz też połączyć tę metodę uwierzytelniania z dotychczasowym użytkownikiem. Na przykład użytkownik, który wcześniej uwierzytelnił się u innego dostawcy, np. za pomocą numeru telefonu, może dodać tę metodę logowania do swojego dotychczasowego konta.

Różnica polega na tym, że druga połowa operacji:

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

Można go też użyć do ponownego uwierzytelnienia użytkownika, który używa linku e-mail, przed wykonaniem operacji wrażliwej.

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

Ponieważ jednak proces może zakończyć się na innym urządzeniu, na którym pierwotny użytkownik nie był zalogowany, może on nie zostać ukończony. W takim przypadku użytkownik może zobaczyć komunikat o błędzie, który zmusza go do otwarcia linku na tym samym urządzeniu. W linku można przekazać pewien stan, aby podać informacje o typie operacji i identyfikatorze użytkownika (UID).

Jeśli projekt został utworzony 15 września 2023 r. lub później, ochrona przed enumeracją adresów e-mail jest domyślnie włączona. Ta funkcja zwiększa bezpieczeństwo kont użytkowników projektu, ale wyłącza metodę fetchSignInMethodsForEmail(), która była wcześniej zalecana do implementacji procesów z identyfikatorem na pierwszym miejscu.

Możesz wyłączyć ochronę przed wyliczaniem adresów e-mail w przypadku swojego projektu, ale nie zalecamy tego.

Aby dowiedzieć się więcej, zapoznaj się z dokumentacją dotyczącą ochrony przed wyliczaniem adresów e-mail.

Dalsze kroki

Gdy użytkownik zaloguje się po raz pierwszy, zostanie utworzone nowe konto użytkownika i połączone z danymi logowania, czyli nazwą użytkownika i hasłem, numerem telefonu lub informacjami dostawcy uwierzytelniania, za pomocą których użytkownik się zalogował. To nowe konto jest przechowywane w projekcie Firebase i może służyć do identyfikowania użytkownika we wszystkich aplikacjach w projekcie, niezależnie od tego, jak użytkownik się loguje.

  • W swoich aplikacjach możesz pobrać podstawowe informacje o profilu użytkownika z obiektu FirebaseUser. Zobacz sekcję Zarządzanie użytkownikami.

  • W regułach Firebase Realtime DatabaseCloud Storage Regułach bezpieczeństwa możesz pobrać z zmiennej auth unikalny identyfikator zalogowanego użytkownika i używać go do kontrolowania dostępu użytkownika do danych.

Możesz zezwolić użytkownikom na logowanie się w aplikacji za pomocą danych uwierzytelniających od różnych dostawców, łącząc je z dotychczasowym kontem użytkownika.

Aby wylogować użytkownika, wywołaj funkcję signOut:

Kotlin

Firebase.auth.signOut()

Java

FirebaseAuth.getInstance().signOut();