Google is committed to advancing racial equity for Black communities. See how.
本頁面由 Cloud Translation API 翻譯而成。
Switch to English

使用Android中的電子郵件鏈接對Firebase進行身份驗證

您可以通過向用戶發送包含鏈接的電子郵件來使用Firebase身份驗證來登錄用戶,他們可以單擊該鏈接來登錄。在此過程中,還將驗證用戶的電子郵件地址。

通過電子郵件登錄有很多好處:

  • 低摩擦註冊和登錄。
  • 降低跨應用程序重複使用密碼的風險,這甚至會損害精選密碼的安全性。
  • 在驗證用戶身份的同時還可以驗證用戶是否是電子郵件地址的合法所有者。
  • 用戶只需要一個可訪問的電子郵件帳戶即可登錄。不需要電話號碼或社交媒體帳戶的所有權。
  • 用戶無需提供(或記住)密碼即可安全登錄,這在移動設備上可能很麻煩。
  • 以前使用電子郵件標識符(密碼或聯盟身份)登錄的現有用戶可以升級為僅使用電子郵件登錄。例如,忘記密碼的用戶仍可以登錄而無需重置密碼。

在你開始之前

設置您的Android項目

  1. 如果尚未將Firebase添加到您的Android項目中
  2. 在項目級別的build.gradle文件中,確保在buildscriptallprojects部分中都包含Google的Maven存儲庫。
  3. 將Firebase身份驗證Android庫和Google Play服務的依賴項添加到模塊(應用程序級)Gradle文件(通常為app/build.gradle )中:

     implementation 'com.google.firebase:firebase-auth:19.3.2'
    implementation 'com.google.android.gms:play-services-auth:18.1.0'
     

要通過電子郵件鏈接登錄用戶,您必須首先為Firebase項目啟用電子郵件提供程序和電子郵件鏈接登錄方法:

  1. Firebase控制台中 ,打開“ 身份驗證”部分。
  2. 在“ 登錄方法”選項卡上,啟用“ 電子郵件/密碼”提供程序。請注意,必須啟用電子郵件/密碼登錄才能使用電子郵件鏈接登錄。
  3. 在同一部分中,啟用“ 電子郵件鏈接(無密碼登錄)”登錄方法。
  4. 點擊保存

要啟動身份驗證流程,請向用戶顯示一個界​​面,提示用戶提供其電子郵件地址,然後調用sendSignInLinkToEmail以請求Firebase將身份驗證鏈接發送到用戶的電子郵件。

  1. 構造ActionCodeSettings對象,該對象為Firebase提供有關如何構造電子郵件鏈接的說明。設置以下字段:

    • url :要嵌入的深層鏈接以及要傳遞的任何其他狀態。鏈接的域必須在授權域的Firebase控制台列表中列入白名單,可通過轉到“登錄方法”選項卡(“身份驗證”->“登錄方法”)找到該列表。如果未在其設備上安裝該應用程序且該應用程序無法安裝,則該鏈接會將用戶重定向到此URL。
    • androidPackageNameIOSBundleId :在Android或iOS設備上打開登錄鏈接時要使用的應用。詳細了解如何配置Firebase動態鏈接以通過移動應用程序打開電子郵件操作鏈接。
    • handleCodeInApp :設置為true。與其他帶外電子郵件操作(密碼重置和電子郵件驗證)不同,登錄操作必須始終在應用程序中完成。這是因為,在流程結束時,預計用戶將被登錄並且其Auth狀態在應用程序中保持不變。
    • dynamicLinkDomain :當為一個項目定義了多個自定義動態鏈接域時,請指定要通過指定的移動應用程序打開鏈接時要使用哪個域(例如example.page.link )。否則,將自動選擇第一個域。

    爪哇

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

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

    要了解有關ActionCodeSettings的更多信息,請參閱“ 電子郵件操作中通過狀態”部分。

  2. 向用戶詢問他們的電子郵件。

  3. 將身份驗證鏈接發送到用戶的電子郵件,並保存用戶的電子郵件,以防用戶在同一設備上完成電子郵件登錄。

    爪哇

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

    Kotlin + KTX

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

安全問題

為防止使用登錄鏈接以意外用戶身份或在意外設備上登錄,Firebase Auth要求在完成登錄流程時提供用戶的電子郵件地址。為了使登錄成功,此電子郵件地址必須與登錄鏈接最初發送到的地址匹配。

通過在發送登錄電子郵件時在本地存儲其電子郵件地址(例如使用SharedPreferences),可以在請求鏈接的同一設備上打開登錄鏈接的用戶簡化此流程。然後,使用該地址完成流程。不要在重定向URL參數中傳遞用戶的電子郵件並重新使用它,因為這可能會啟用會話注入。

登錄完成後,將從用戶中刪除任何以前未驗證的登錄機制,並且所有現有會話都將無效。例如,如果某人以前使用相同的電子郵件和密碼創建了未經驗證的帳戶,則將刪除用戶密碼,以防止聲稱擁有所有權並創建該未經驗證的帳戶的冒用者再次使用未經驗證的電子郵件和密碼登錄。

另外,還要確保在生產環境中使用HTTPS URL,以避免中間服務器可能攔截您的鏈接。

在Android應用中完成登錄

Firebase身份驗證使用Firebase動態鏈接將電子郵件鏈接發送到移動設備。為了通過移動應用程序完成登錄,必須將應用程序配置為檢測傳入的應用程序鏈接,解析基礎深層鏈接,然後完成登錄。

當發送要在移動應用程序中打開的鏈接時,Firebase Auth使用Firebase動態鏈接 。為了使用此功能, 必須在Firebase控制台中配置動態鏈接。

  1. 啟用Firebase動態鏈接:

    1. Firebase控制台中 ,打開“ 動態鏈接”部分。
    2. 如果您尚未接受動態鏈接條款並創建了動態鏈接域,請立即執行。

      如果您已經創建了動態鏈接域,請記下它。動態鏈接域通常類似於以下示例:

      example.page.link

      配置iOS或Android應用程序以攔截傳入鏈接時,將需要此值。

  2. 配置Android應用程序:

    1. 為了處理來自您的Android應用程序的這些鏈接,需要在Firebase控制台項目設置中指定Android包名稱。另外,需要提供應用程序證書的SHA-1和SHA-256。
    2. 現在,您已經添加了動態鏈接域,並確保正確配置了Android應用程序,動態鏈接將從啟動程序活動開始重定向到您的應用程序。
    3. 如果您希望動態鏈接重定向到特定活動,則需要在AndroidManifest.xml文件中配置一個意圖過濾器。這可以通過在意圖過濾器中指定動態鏈接域或電子郵件操作處理程序來完成。默認情況下,電子郵件操作處理程序託管在如下示例所示的域中:
       PROJECT_ID .firebaseapp.com/
    4. 注意事項:
      1. 不要在意圖過濾器中指定您在actionCodeSettings上設置的URL。
      2. 創建動態鏈接域時,您可能還創建了一個簡短的URL鏈接。這個簡短的網址不會被傳遞; 不要將您的意圖過濾器配置為使用android:pathPrefix屬性捕獲它。這意味著您將無法在應用程序的不同部分捕獲不同的動態鏈接。但是,您可以檢查鏈接中的mode查詢參數以查看嘗試執行的操作,或使用SDK方法(例如isSignInWithEmailLink查看您的應用程序收到的鏈接是否符合您的要求。
    5. 有關接收動態鏈接的更多信息,請參閱接收Android動態鏈接說明

如上所述收到鏈接後,請驗證該鏈接是否適用於電子郵件鏈接身份驗證並完成登錄。

爪哇

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

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 = "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)
                }
            }
}

要了解有關如何在iOS應用程序中處理帶有電子郵件鏈接的登錄的更多信息,請參閱iOS指南

要了解如何在Web應用程序中處理帶有電子郵件鏈接的登錄,請參閱Web指南

您也可以將此身份驗證方法鏈接到現有用戶。例如,先前通過其他提供商(例如電話號碼)進行身份驗證的用戶可以將這種登錄方法添加到其現有帳戶中。

區別在於操作的後半部分:

爪哇

// 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 + 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)
            }
        }

在運行敏感操作之前,此方法還可用於重新驗證電子郵件鏈接用戶。

爪哇

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

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

但是,由於該流程可能會在未登錄原始用戶的其他設備上結束,因此該流程可能無法完成。在這種情況下,可以向用戶顯示錯誤,迫使他們打開同一設備上的鏈接。可以在鏈接中傳遞某些狀態,以提供有關操作類型和用戶uid的信息。

如果您同時支持密碼登錄和基於鏈接的電子郵件登錄, fetchSignInMethodsForEmail密碼/鏈接用戶的登錄方法,請使用fetchSignInMethodsForEmail 。這對於首先要求用戶提供電子郵件然後提供登錄方法的標識符優先流很有用:

爪哇

auth.fetchSignInMethodsForEmail(email)
        .addOnCompleteListener(new OnCompleteListener<SignInMethodQueryResult>() {
            @Override
            public void onComplete(@NonNull Task<SignInMethodQueryResult> task) {
                if (task.isSuccessful()) {
                    SignInMethodQueryResult result = task.getResult();
                    List<String> signInMethods = result.getSignInMethods();
                    if (signInMethods.contains(EmailAuthProvider.EMAIL_PASSWORD_SIGN_IN_METHOD)) {
                        // User can sign in with email/password
                    } else if (signInMethods.contains(EmailAuthProvider.EMAIL_LINK_SIGN_IN_METHOD)) {
                        // User can sign in with email/link
                    }
                } else {
                    Log.e(TAG, "Error getting sign in methods for user", task.getException());
                }
            }
        });

Kotlin + KTX

Firebase.auth.fetchSignInMethodsForEmail(email)
        .addOnSuccessListener { result ->
            val signInMethods = result.signInMethods!!
            if (signInMethods.contains(EmailAuthProvider.EMAIL_PASSWORD_SIGN_IN_METHOD)) {
                // User can sign in with email/password
            } else if (signInMethods.contains(EmailAuthProvider.EMAIL_LINK_SIGN_IN_METHOD)) {
                // User can sign in with email/link
            }
        }
        .addOnFailureListener { exception ->
            Log.e(TAG, "Error getting sign in methods for user", exception)
        }

如上所述,電子郵件/密碼和電子郵件/鏈接被視為具有不同登錄方法的相同EmailAuthProvider (相同PROVIDER_ID )。

下一步

用戶首次登錄後,將創建一個新的用戶帳戶並將其鏈接到該用戶登錄的憑據(即用戶名和密碼,電話號碼或身份驗證提供者信息)。此新帳戶存儲為Firebase項目的一部分,無論用戶如何登錄,都可以用來在項目中的每個應用程序中識別用戶。

  • 在您的應用程序中,您可以從FirebaseUser對象獲取用戶的基本配置文件信息。請參閱管理用戶

  • 在Firebase實時數據庫和雲存儲安全規則中 ,您可以從auth變量中獲取登錄用戶的唯一用戶ID,然後使用它來控制用戶可以訪問哪些數據。

通過將身份驗證提供程序憑據鏈接到現有用戶帳戶,可以允許用戶使用多個身份驗證提供程序登錄您的應用程序

要註銷用戶,請致電signOut

爪哇

FirebaseAuth.getInstance().signOut();

Kotlin + KTX

Firebase.auth.signOut()