אימות עם Firebase באמצעות קישור אימייל בפלטפורמות של Apple

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

יש יתרונות רבים לכניסה באמצעות אימייל:

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

לפני שמתחילים

שימוש ב-Swift Package Manager כדי להתקין ולנהל יחסי תלות ב-Firebase.

  1. ב-Xcode, כשפרויקט האפליקציה פתוח, עוברים אל קובץ > הוספת חבילות.
  2. כשמופיעה בקשה, מוסיפים את המאגר של Firebase SDK לפלטפורמות של Apple:
  3.   https://github.com/firebase/firebase-ios-sdk.git
  4. בוחרים את הספרייה Firebase Authentication.
  5. מוסיפים את הדגל -ObjC לקטע Other Linker Flags (דגלים אחרים של קישור) בהגדרות ה-build של היעד.
  6. בסיום, Xcode יתחיל לפתור את יחסי התלות ולהוריד אותם באופן אוטומטי ברקע.

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

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

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

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

    • url: קישור העומק להטמעה וכל מצב נוסף שצריך להעביר. הדומיין של הקישור צריך להיכלל ברשימת ההיתרים של הדומיינים המורשים במסוף Firebase. כדי למצוא את הרשימה הזו, עוברים לכרטיסייה 'שיטת כניסה' (Authentication -> Sign-in method).
    • iOSBundleID ו-androidPackageName : האפליקציות שבהן נעשה שימוש כשהקישור לכניסה נפתח במכשיר Android או Apple. איך מגדירים קישורים דינמיים של Firebase כדי לפתוח קישורי פעולה באימייל דרך אפליקציות לנייד
    • handleCodeInApp: מגדירים כ-true. תמיד צריך להשלים את פעולת הכניסה באפליקציה, בניגוד לפעולות אחרות באימייל מחוץ לצ'אט (איפוס סיסמה ואימותים באימייל). הסיבה לכך היא שבסוף התהליך, המשתמש אמור להיות מחובר לחשבון ומצב האימות שלו נשמר באפליקציה.
    • dynamicLinkDomain: כשמגדירים כמה דומיינים של קישורים דינמיים מותאמים אישית לפרויקט, צריך לציין באיזה מהם להשתמש כשהקישור ייפתח דרך אפליקציה לנייד ספציפית (לדוגמה, example.page.link). אחרת, הדומיין הראשון ייבחר באופן אוטומטי.

    Swift

    let actionCodeSettings = ActionCodeSettings()
    actionCodeSettings.url = URL(string: "https://www.example.com")
    // The sign-in operation has to always be completed in the app.
    actionCodeSettings.handleCodeInApp = true
    actionCodeSettings.setIOSBundleID(Bundle.main.bundleIdentifier!)
    actionCodeSettings.setAndroidPackageName("com.example.android",
                                             installIfNotAvailable: false, minimumVersion: "12")

    Objective-C

    FIRActionCodeSettings *actionCodeSettings = [[FIRActionCodeSettings alloc] init];
    [actionCodeSettings setURL:[NSURL URLWithString:@"https://www.example.com"]];
    // The sign-in operation has to always be completed in the app.
    actionCodeSettings.handleCodeInApp = YES;
    [actionCodeSettings setIOSBundleID:[[NSBundle mainBundle] bundleIdentifier]];
    [actionCodeSettings setAndroidPackageName:@"com.example.android"
                        installIfNotAvailable:NO
                               minimumVersion:@"12"];

    מידע נוסף על ActionCodeSettings זמין בקטע העברת מצב בפעולות אימייל.

  2. מבקשים מהמשתמש את כתובת האימייל שלו.

  3. שולחים את הקישור לאימות לכתובת האימייל של המשתמש, ושומרים את כתובת האימייל של המשתמש למקרה שהמשתמש ישלים את תהליך הכניסה באמצעות האימייל באותו מכשיר.

    Swift

    Auth.auth().sendSignInLink(toEmail: email,
                               actionCodeSettings: actionCodeSettings) { error in
      // ...
        if let error = error {
          self.showMessagePrompt(error.localizedDescription)
          return
        }
        // The link was successfully sent. Inform the user.
        // Save the email locally so you don't need to ask the user for it again
        // if they open the link on the same device.
        UserDefaults.standard.set(email, forKey: "Email")
        self.showMessagePrompt("Check your email for link")
        // ...
    }

    Objective-C

    [[FIRAuth auth] sendSignInLinkToEmail:email
                       actionCodeSettings:actionCodeSettings
                               completion:^(NSError *_Nullable error) {
      // ...
        if (error) {
          [self showMessagePrompt:error.localizedDescription];
           return;
        }
        // The link was successfully sent. Inform the user.
        // Save the email locally so you don't need to ask the user for it again
        // if they open the link on the same device.
        [NSUserDefaults.standardUserDefaults setObject:email forKey:@"Email"];
        [self showMessagePrompt:@"Check your email for link"];
        // ...
    }];

חששות אבטחה

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

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

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

השלמת הכניסה באפליקציה לנייד של Apple

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

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

  1. מפעילים את הקישורים הדינמיים ב-Firebase:

    1. במסוף Firebase, פותחים את הקטע Dynamic Links.
    2. אם עדיין לא אישרתם את התנאים של Dynamic Links ויצרתם דומיין Dynamic Links, עליכם לעשות זאת עכשיו.

      אם כבר יצרתם דומיין Dynamic Links, שימו לב אליו. דומיין Dynamic Links בדרך כלל נראה כמו הדוגמה הבאה:

      example.page.link

      תצטרכו את הערך הזה כשתקבעו שהאפליקציה שלכם ל-Apple או ל-Android תוכל ליירט את הקישור הנכנס.

  2. הגדרת אפליקציות של Apple:

    1. אם אתם מתכננים לטפל בקישורים האלה מהאפליקציה, צריך לציין את מזהה החבילה בהגדרות הפרויקט במסוף Firebase. בנוסף, צריך לציין את מזהה App Store ואת מזהה צוות הפיתוח של Apple.
    2. בנוסף, תצטרכו להגדיר את הדומיין של בורר הפעולות באימייל בתור דומיין משויך ביכולות האפליקציה. כברירת מחדל, הכלי לטיפול בפעולות אימייל מתארח בדומיין כמו בדוגמה הבאה:
      APP_ID.firebaseapp.com
    3. אם אתם מתכננים להפיץ את האפליקציה לגרסאות iOS 8 ומטה, תצטרכו להגדיר את מזהה החבילה כסכימה בהתאמה אישית לכתובות URL נכנסות.
    4. מידע נוסף זמין במאמר קבלת קישורים דינמיים בפלטפורמה של Apple.

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

Swift

if Auth.auth().isSignIn(withEmailLink: link) {
        Auth.auth().signIn(withEmail: email, link: self.link) { user, error in
          // ...
        }
}

Objective-C

if ([[FIRAuth auth] isSignInWithEmailLink:link]) {
    [[FIRAuth auth] signInWithEmail:email
                               link:link
                         completion:^(FIRAuthDataResult * _Nullable authResult, NSError * _Nullable error) {
      // ...
    }];
}

במאמר המדריך ל-Android מוסבר איך מטפלים בכניסה באמצעות קישור לאימייל באפליקציה ל-Android.

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

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

ההבדל יהיה במחצית השנייה של הפעולה:

Swift

  let credential = EmailAuthCredential.credential(withEmail:email
                                                       link:link)
  Auth.auth().currentUser?.link(with: credential) { authData, error in
    if (error) {
      // And error occurred during linking.
      return
    }
    // The provider was successfully linked.
    // The phone user can now sign in with their phone number or email.
  }

Objective-C

  FIRAuthCredential *credential =
      [FIREmailAuthProvider credentialWithEmail:email link:link];
  [FIRAuth auth].currentUser
      linkWithCredential:credential
              completion:^(FIRAuthDataResult *_Nullable result,
                           NSError *_Nullable error) {
    if (error) {
      // And error occurred during linking.
      return;
    }
    // The provider was successfully linked.
    // The phone user can now sign in with their phone number or email.
  }];

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

Swift

  let credential = EmailAuthProvider.credential(withEmail:email
                                                       link:link)
  Auth.auth().currentUser?.reauthenticate(with: credential) { authData, error in
    if (error) {
      // And error occurred during re-authentication.
      return
    }
    // The user was successfully re-authenticated.
  }

Objective-C

  FIRAuthCredential *credential =
      [FIREmailAuthCredential credentialWithEmail:email link:link];
  [FIRAuth auth].currentUser
      reauthenticateWithCredential:credential
                        completion:^(FIRAuthDataResult *_Nullable result,
                                     NSError *_Nullable error) {
    if (error) {
      // And error occurred during re-authentication
      return;
    }
    // The user was successfully re-authenticated.
  }];

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

אם יצרתם את הפרויקט ב-15 בספטמבר 2023 או לאחר מכן, ההגנה מפני ספירת כתובות אימייל מופעלת כברירת מחדל. התכונה הזו משפרת את האבטחה של חשבונות המשתמשים בפרויקט, אבל היא משביתה את השיטה fetchSignInMethodsForEmail(), שבעבר המלצנו להשתמש בה כדי להטמיע תהליכים שמתחילים במזהה.

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

למידע נוסף, עיינו במסמכי העזרה בנושא הגנה מפני ספירת כתובות אימייל.

השלבים הבאים

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

  • באפליקציות, אפשר לקבל את פרטי הפרופיל הבסיסיים של המשתמש מהאובייקט User . ניהול משתמשים

  • בכללי האבטחה של Firebase Realtime Database ו-Cloud Storage, אפשר לקבל את מזהה המשתמש הייחודי של המשתמש שנכנס לחשבון מהמשתנה auth, ולהשתמש בו כדי לקבוע לאילו נתונים למשתמש תהיה גישה.

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

כדי להוציא משתמש מהחשבון, קוראים ל- signOut:.

Swift

let firebaseAuth = Auth.auth()
do {
  try firebaseAuth.signOut()
} catch let signOutError as NSError {
  print("Error signing out: %@", signOutError)
}

Objective-C

NSError *signOutError;
BOOL status = [[FIRAuth auth] signOut:&signOutError];
if (!status) {
  NSLog(@"Error signing out: %@", signOutError);
  return;
}

מומלץ גם להוסיף קוד לטיפול בשגיאות לכל מגוון השגיאות באימות. מידע נוסף זמין במאמר טיפול בשגיאות.