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

Możesz użyć Uwierzytelniania Firebase, aby zalogować użytkownika, wysyłając mu e-maila z linkiem, który może kliknąć, aby się zalogować. W trakcie tej procedury weryfikowany jest także adres e-mail użytkownika.

Logowanie się przez e-maila ma wiele zalet:

  • Łatwa rejestracja i logowanie.
  • Mniejsze ryzyko ponownego użycia hasła w różnych aplikacjach, co może zagrażać bezpieczeństwu nawet dobrze wybranych haseł.
  • Możliwość uwierzytelniania użytkownika przy jednoczesnym sprawdzaniu, czy użytkownik jest prawowitym właścicielem adresu e-mail.
  • Do zalogowania się użytkownik potrzebuje tylko łatwo dostępnego konta e-mail. Nie trzeba mieć 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 sfederowanego), może zostać uaktualniony, aby mógł logować się przy użyciu samego adresu e-mail. Na przykład użytkownik, który zapomniał hasła, może się zalogować bez konieczności jego resetowania.

Zanim zaczniesz

Skonfiguruj projekt na Androida

  1. Dodaj Firebase do swojego projektu na Androida, jeśli jeszcze go nie masz.

  2. W pliku Gradle na poziomie modułu (na poziomie aplikacji) (zwykle <project>/<app-module>/build.gradle.kts lub <project>/<app-module>/build.gradle) dodaj zależność do biblioteki uwierzytelniania Firebase na Androida. Do kontrolowania obsługi wersji biblioteki zalecamy używanie BOM Firebase na Androida.

    Podczas konfigurowania Uwierzytelniania Firebase 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.1.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.2.0")
    }

    Dzięki wykorzystaniu BM od Firebase Android Twoja aplikacja zawsze będzie używała zgodnych wersji bibliotek Firebase na Androida.

    (Alternatywnie) Dodaj zależności biblioteki Firebase bez użycia BoM.

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

    Pamiętaj, że jeśli w aplikacji używasz wielu bibliotek Firebase, zdecydowanie zalecamy korzystanie z BoM do zarządzania wersjami biblioteki. Zapewni to zgodność wszystkich wersji.

    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.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.2.0")
    }
    Szukasz modułu biblioteki dotyczącego konkretnego narzędzia Kotlin? Od października 2023 r. (Firebase BoM w wersji 32.5.0) deweloperzy korzystający z Kotlin i Javy mogą korzystać z modułu biblioteki głównej (szczegółowe informacje znajdziesz w odpowiedziach na najczęstsze pytania na temat tej inicjatywy).

Aby logować użytkowników za pomocą linku e-mail, musisz najpierw włączyć w projekcie Firebase metodę logowania dostawcy poczty e-mail i linku e-mail:

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

Aby rozpocząć proces uwierzytelniania, pokaż użytkownikowi interfejs, który prosi o podanie adresu e-mail, a następnie wywołaj sendSignInLinkToEmail, aby poprosić Firebase o wysłanie linku uwierzytelniającego na adres e-mail użytkownika.

  1. Utwórz obiekt ActionCodeSettings, który udostępnia Firebase instrukcje tworzenia linku do e-maila. Ustaw wartości w tych polach:

    • url: precyzyjny link do umieszczenia i dodatkowy stan do przekazania. Domena linku musi być na białej liście autoryzowanych domen w konsoli Firebase. Znajdziesz ją na karcie Metoda logowania (Uwierzytelnianie -> Metoda logowania). Jeśli użytkownik nie ma zainstalowanej aplikacji na urządzeniu i nie można jej zainstalować, link przekieruje użytkownika na ten adres URL.
    • androidPackageName i IOSBundleId: aplikacje, które będą używane po otwarciu linku logowania na urządzeniu z Androidem lub urządzeniu firmy Apple. Dowiedz się więcej o konfigurowaniu Linków dynamicznych Firebase pod kątem otwierania w aplikacjach mobilnych linków do działań związanych z e-mailem.
    • handleCodeInApp: ma wartość prawda. Logowanie musi zawsze odbywać się w aplikacji – inaczej niż w przypadku innych działań związanych z wysyłaniem e-maili spoza zespołu (resetowanie hasła czy potwierdzanie adresu e-mail). Dzieje się tak, ponieważ użytkownik powinien być zalogowany na końcu procesu, a stan uwierzytelniania w aplikacji pozostaje niezmieniony.
    • dynamicLinkDomain: jeśli w projekcie jest zdefiniowanych 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 (na przykład example.page.link). W przeciwnym razie automatycznie wybierana jest pierwsza domena.

    Kotlin+KTX

    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 ActionCodeSettings znajdziesz w sekcji Passing State in Email Actions (Informacje o stanie przekazywania e-maili).

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

  3. Wyślij link uwierzytelniający na adres e-mail użytkownika i zapisz go na wypadek, gdyby logował się on na tym samym urządzeniu.

    Kotlin+KTX

    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życiu linku umożliwiającego zalogowanie się jako niezamierzony użytkownik lub na niezamierzonym urządzeniu, Uwierzytelnianie Firebase wymaga podania adresu e-mail użytkownika podczas logowania. Aby logowanie się udało, ten adres e-mail musi być zgodny z adresem, na który pierwotnie został wysłany link 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 go poproszą, przechowując ich adres e-mail lokalnie (np. za pomocą opcji SharedPreferences) podczas wysyłania e-maila dotyczącego logowania. Następnie użyj tego adresu, aby dokończyć proces. Nie przekazuj adresu e-mail użytkownika w parametrach przekierowania i nie używaj go ponownie, ponieważ może to umożliwić wstrzykiwanie sesji.

Po zakończeniu logowania wszystkie wcześniejsze niezweryfikowane mechanizmy logowania zostaną usunięte z konta użytkownika, a wszystkie istniejące sesje zostaną unieważnione. Jeśli na przykład ktoś utworzył wcześniej niezweryfikowane konto z tym samym adresem e-mail i hasłem, jego hasło zostanie usunięte, aby osoba podszywająca się pod użytkownika, która zgłosiła prawa własności i utworzyła niezweryfikowane konto, nie mogła zalogować się ponownie przy użyciu niezweryfikowanego adresu e-mail i hasła.

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

Ukończenie logowania w aplikacji na Androida

Uwierzytelnianie Firebase wykorzystuje Linki dynamiczne Firebase do wysyłania e-maila z linkiem na urządzenie mobilne. W przypadku logowania się za pomocą aplikacji mobilnej trzeba skonfigurować aplikację tak, aby wykrywała przychodzący link do aplikacji, analizował odpowiedni precyzyjny link, a następnie dokończył logowanie.

Uwierzytelnianie Firebase używa Linków dynamicznych Firebase do wysyłania linku, który ma otwierać się w aplikacji mobilnej. Aby korzystać z tej funkcji, Linki dynamiczne muszą być skonfigurowane w konsoli Firebase.

  1. Włącz Linki dynamiczne Firebase:

    1. W konsoli Firebase otwórz sekcję Linki dynamiczne.
    2. Jeśli warunki korzystania z linków dynamicznych nie zostały jeszcze zaakceptowane, a domena linków dynamicznych została utworzona, zrób to teraz.

      Jeśli masz już utworzoną domenę linków dynamicznych, zanotuj ją. Domena linków dynamicznych wygląda zazwyczaj tak:

      example.page.link

      Będzie ona potrzebna podczas konfigurowania aplikacji na Apple lub Androida tak, aby przechwytywała link przychodzący.

  2. Konfigurowanie aplikacji na Androida:

    1. Aby obsługiwać te linki z aplikacji na Androida, musisz określić nazwę pakietu na Androida w ustawieniach projektu w konsoli Firebase. Dodatkowo należy podać wartości 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 będzie przekierowywać do niej, zaczynając od działania programu uruchamiającego.
    3. Jeśli chcesz, aby link dynamiczny kierował do konkretnej aktywności, skonfiguruj w pliku AndroidManifest.xml filtr intencji. Można to zrobić, określając domenę linku dynamicznego lub moduł obsługi działań e-mail w filtrze intencji. Domyślnie moduł obsługi działań związanych z pocztą e-mail jest hostowany w domenie, tak jak w tym przykładzie:
      PROJECT_ID.firebaseapp.com/
    4. Zastrzeżenia:
      1. Nie określaj adresu URL ustawionego w actionCodeSettings w filtrze intencji.
      2. Podczas tworzenia domeny linku dynamicznego możesz też utworzyć krótki link URL. Ten krótki adres URL nie będzie przekazywany. Nie konfiguruj filtra intencji, aby przechwytywać go za pomocą atrybutu android:pathPrefix. Oznacza to, że nie możesz przechwytywać różnych linków dynamicznych w różnych częściach aplikacji. Możesz jednak sprawdzić parametr zapytania mode w linku, aby zobaczyć, jaka operacja ma zostać wykonana, lub użyć metod SDK takich jak isSignInWithEmailLink, aby sprawdzić, czy link odebrany przez aplikację działa zgodnie z oczekiwaniami.
    5. Więcej informacji o odbieraniu linków dynamicznych znajdziesz w instrukcjach odbierania linków dynamicznych na Androida.

Po otrzymaniu linku zgodnie z opisem powyżej sprawdź, czy służy on do uwierzytelniania linków w e-mailach, i dokończ logowanie.

Kotlin+KTX

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 = "[email protected]"

    // 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 = "[email protected]";

    // 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 obsłudze logowania za pomocą linku z e-maila w aplikacji Apple znajdziesz w przewodniku po platformach Apple.

Informacje o tym, jak postępować w przypadku logowania się za pomocą linku z e-maila w aplikacji internetowej, znajdziesz w przewodniku internetowym.

Tę metodę uwierzytelniania możesz też powiązać z istniejącym użytkownikiem. Na przykład użytkownik, który wcześniej uwierzytelnił się w usłudze innego dostawcy (np. za pomocą numeru telefonu), może dodać tę metodę logowania do swojego konta.

Różnica miałaby miejsce w drugiej połowie operacji:

Kotlin+KTX

// 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że też służyć do ponownego uwierzytelnienia użytkownika linku z adresem e-mail przed wykonaniem operacji poufnej.

Kotlin+KTX

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

Proces ten może jednak zakończyć się na innym urządzeniu, na którym nie był zalogowany pierwotny użytkownik, więc proces może nie zostać ukończony. W takim przypadku użytkownikowi może zostać wyświetlony komunikat o błędzie, który zmusi go do otwarcia linku na tym samym urządzeniu. Niektóre stany można przekazywać w linku, aby podawać informacje o typie operacji i identyfikatorze UID użytkownika.

Jeśli Twój projekt został utworzony 15 września 2023 r. lub później, ochrona przed wyliczeniami e-maili jest domyślnie włączona. Ta funkcja zwiększa bezpieczeństwo kont użytkowników projektu, ale wyłącza metodę fetchSignInMethodsForEmail(), którą wcześniej zalecaliśmy przy implementacji procesów opartych na identyfikatorze.

Chociaż w swoim projekcie możesz wyłączyć ochronę przed wyliczeniami e-maili, odradzamy to.

Więcej informacji znajdziesz w dokumentacji na temat ochrony przed wyliczeniami w e-mailach.

Dalsze kroki

Gdy użytkownik zaloguje się po raz pierwszy, zostaje utworzone nowe konto użytkownika powiązane z danymi logowania (tj. nazwą użytkownika i hasłem, numerem telefonu lub informacjami o dostawcy uwierzytelniania), przy użyciu którego się zalogował. Nowe konto jest przechowywane w ramach projektu Firebase i może służyć do identyfikowania użytkowników we wszystkich aplikacjach w projekcie niezależnie od tego, jak się on zaloguje.

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

  • W Regułach zabezpieczeń Bazy danych czasu rzeczywistego Firebase i Cloud Storage możesz uzyskać unikalny identyfikator zalogowanego użytkownika ze zmiennej auth i za jego pomocą kontrolować, do jakich danych ma on dostęp.

Jeśli chcesz zezwolić użytkownikom na logowanie się w Twojej aplikacji za pomocą różnych dostawców uwierzytelniania, możesz połączyć dane logowania dostawcy uwierzytelniania z istniejącym kontem użytkownika.

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

Kotlin+KTX

Firebase.auth.signOut()

Java

FirebaseAuth.getInstance().signOut();