אימות עם 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 Services.

    dependencies {
        // Import the BoM for the Firebase platform
        implementation(platform("com.google.firebase:firebase-bom:33.8.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: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")
    }
    מחפשים מודול ספרייה ספציפי ל-Kotlin? החל מ-אוקטובר 2023 (Firebase BoM 32.5.0), מפתחי Kotlin ומפתחי Java יוכלו להסתמך על מודול הספרייה הראשי (פרטים נוספים זמינים בשאלות הנפוצות בנושא היוזמה הזו).

הפעלת כניסה באמצעות קישור לאימייל בפרויקט Firebase

כדי לאפשר למשתמשים להיכנס באמצעות קישור באימייל, קודם צריך להפעיל את ספק האימייל ואת שיטת הכניסה באמצעות קישור באימייל בפרויקט Firebase:

  1. במסוף Firebase, פותחים את הקטע Auth.
  2. בכרטיסייה Sign in method (שיטת כניסה), מפעילים את הספק Email/Password (אימייל/סיסמה). חשוב לזכור: כדי להשתמש בכניסה באמצעות קישור לאימייל, צריך להפעיל את הכניסה באמצעות כתובת אימייל/סיסמה.
  3. באותו קטע, מפעילים את שיטת הכניסה קישור לאימייל (כניסה ללא סיסמה).
  4. לוחצים על שמירה.

כדי להתחיל את תהליך האימות, מציגים למשתמש ממשק שמבקש ממנו לספק את כתובת האימייל שלו, ולאחר מכן קוראים ל-sendSignInLinkToEmail כדי לבקש מ-Firebase לשלוח את הקישור לאימות לכתובת האימייל של המשתמש.

  1. יוצרים את האובייקט ActionCodeSettings, שמספק ל-Firebase הוראות ליצירת הקישור באימייל. מגדירים את השדות הבאים:

    • url: קישור העומק להטמעה וכל מצב נוסף שרוצים להעביר. הדומיין של הקישור צריך להיכלל ברשימת ההיתרים של הדומיינים המורשים במסוף Firebase. כדי למצוא את הרשימה הזו, עוברים לכרטיסייה 'שיטת כניסה' (Authentication -> Sign-in method). הקישור יפנה את המשתמש לכתובת ה-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 להפניה אוטומטית ולהשתמש בה שוב, כי הפעולות האלה עלולות לאפשר הזרקות של סשנים.

בסיום הכניסה, כל מנגנון כניסה לא מאומת קודם יוסר מהמשתמש וכל הסשנים הקיימים יבוטלו. לדוגמה, אם מישהו יצר בעבר חשבון לא מאומת עם אותה כתובת אימייל וסיסמה, הסיסמה של המשתמש תוסר כדי למנוע מהמתחזה שטען לבעלות על החשבון הזה ויצר אותו להיכנס שוב באמצעות כתובת האימייל והסיסמה הלא מאומתות.

בנוסף, חשוב להשתמש בכתובת URL מסוג HTTPS בסביבת הייצור כדי למנוע משרתי ביניים ליירט את הקישור.

השלמת הכניסה באפליקציה ל-Android

Firebase Authentication משתמש ב-Firebase Hosting כדי לשלוח את הקישור באימייל למכשיר נייד. כדי להשלים את הכניסה דרך אפליקציה לנייד, צריך להגדיר את האפליקציה כך שתזהה את הקישור לאפליקציה הנכנס, תנתח את קישור העומק הבסיסי ואז תשלים את הכניסה. מידע נוסף זמין במסמכי העזרה בנושא קישורים לאפליקציות ל-Android.

הגדרה של Firebase Hosting

Firebase Authentication משתמש בדומיינים של Firebase Hosting כשיוצרים ושולחים קישור שנועד להיפתח באפליקציה לנייד. כבר הוגדר עבורכם דומיין Firebase Hosting כברירת מחדל.

  1. מגדירים דומיינים של Firebase Hosting:

    במסוף Firebase, פותחים את הקטע Hosting.

    • אם רוצים להשתמש בדומיין ברירת המחדל בקישור לאימייל שנפתח באפליקציות לנייד, עוברים לאתר ברירת המחדל ומתעדים את הדומיין 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());
                }
            }
        });

עם זאת, מכיוון שהתהליך עשוי להסתיים במכשיר אחר שבו המשתמש המקורי לא היה מחובר לחשבון, יכול להיות שהתהליך לא יושלם. במקרה כזה, אפשר להציג למשתמש הודעת שגיאה כדי לאלץ אותו לפתוח את הקישור באותו מכשיר. אפשר להעביר מצב מסוים בקישור כדי לספק מידע על סוג הפעולה ועל מזהה המשתמש.

אימות קישורי אימייל היה מבוסס בעבר על 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();