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

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

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

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

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

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

  1. ב-Xcode, כשפרויקט האפליקציה פתוח, עוברים אל קובץ > הוספת חבילות.
  2. כשמופיעה בקשה, מוסיפים את מאגר ה-SDK של מוצרי הפלטפורמה של Firebase של 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. בכרטיסייה שיטת כניסה, מפעילים את ספק האימייל/סיסמה. הערה שכדי להשתמש בכניסה באמצעות קישור לאימייל, צריך להפעיל את הכניסה לחשבון באמצעות האימייל או הסיסמה.
  3. באותו קטע, מפעילים את שיטת הכניסה קישור לאימייל (כניסה ללא סיסמה).
  4. לוחצים על שמירה.

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

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

    • url: קישור העומק להטמעה וכל מצב נוסף שרוצים להעביר. הדומיין של הקישור צריך להיות מצורף לרשימת ההיתרים של מסוף Firebase של דומיינים מורשים. כדי למצוא אותם בכרטיסייה 'שיטת כניסה', (אימות -> שיטת כניסה).
    • iOSBundleID ו-androidPackageName : האפליקציות לשימוש בזמן קישור לכניסה פותחים את המכשיר במכשיר Android או Apple. הגדרת קישורים דינמיים ב-Firebase כדי לפתוח קישורים לפעולות באימייל דרך אפליקציות לנייד.
    • headCodeInApp: מוגדר כ-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. בנוסף צריך להגדיר את דומיין ה-handler של פעולות האימייל הדומיין המשויך ביכולות האפליקציה שלך. כברירת מחדל, הגורם שמטפל בפעולות באימייל מתארח בדומיין כמו בדוגמה הבאה:
      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;
}

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