אימות באמצעות Apple ו-C++

ניתן לאפשר למשתמשים לבצע אימות באמצעות Firebase באמצעות Apple ID שלהם: באמצעות Firebase SDK כדי לבצע את תהליך הכניסה מקצה לקצה עם OAuth 2.0.

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

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

הצטרפות לתוכנית המפתחים של Apple

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

הגדרת הכניסה באמצעות Apple

צריך להפעיל את הכניסה ל-Apple ולהגדיר אותה בצורה נכונה בפרויקט Firebase. ההגדרות האישיות משתנות בין הפלטפורמות של Android ו-Apple. צריך לפעול לפי "הגדרת כניסה באמצעות Apple" בקטע של פלטפורמות של Apple ו/או מדריכי Android לפני בתהליך.

הפעלת Apple כספק כניסה

  1. במסוף Firebase, פותחים את הקטע אימות. בכרטיסייה Sign in method מפעילים את הספק Apple.
  2. מגדירים את הגדרות הספק של Apple Sign-in:
    1. אם אתם פורסים את האפליקציה רק בפלטפורמות של Apple, תוכלו להשאיר את השדות Service ID,‏ Apple Team ID,‏ private key ו-key ID ריקים.
    2. לקבלת תמיכה במכשירי Android:
      1. מוסיפים את Firebase לפרויקט Android. חשוב לרשום את החתימה של האפליקציה ב-SHA-1 כשמגדירים אותה במסוף Firebase.
      2. במסוף Firebase, פותחים את הקטע Auth. בכרטיסייה Sign in method מפעילים את הספק Apple. יש לציין את מזהה השירות שיצרת בו בקטע הקודם. בנוסף, בקטע של הגדרת תהליך הקוד של OAuth, מציינים את מזהה הצוות ב-Apple, את המפתח הפרטי ואת מזהה המפתח שיצרתם בקטע הקודם.

תאימות לדרישות של Apple לגבי נתונים אנונימיים

התכונה 'כניסה באמצעות חשבון Apple' מאפשרת למשתמשים לבצע אנונימיזציה של הנתונים שלהם, כולל כתובת האימייל שלהם, בזמן הכניסה לחשבון. משתמשים שבוחרים באפשרות הזו יש כתובות אימייל עם הדומיין privaterelay.appleid.com. כשמשתמשים ב'כניסה באמצעות חשבון Apple' באפליקציה, צריך לפעול בהתאם לכללי המדיניות או לתנאים הרלוונטיים של Apple למפתחים בנוגע למזהי Apple האנונימיים האלה.

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

  • קישור כתובת אימייל ל-Apple ID אנונימי או להפך.
  • קישור של מספר טלפון ל-Apple ID אנונימי או להפך
  • לקשר פרטי כניסה לא אנונימיים ברשתות חברתיות (Facebook,‏ Google וכו') ל-Apple ID אנונימי, ולהפך.

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

גישה לכיתה firebase::auth::Auth

המחלקה Auth היא השער לכל הקריאות ל-API.
  1. מוסיפים את קובצי הכותרת 'אימות' ו'אפליקציה':
    #include "firebase/app.h"
    #include "firebase/auth.h"
  2. בקוד האתחול, יוצרים firebase::App.
    #if defined(__ANDROID__)
      firebase::App* app =
          firebase::App::Create(firebase::AppOptions(), my_jni_env, my_activity);
    #else
      firebase::App* app = firebase::App::Create(firebase::AppOptions());
    #endif  // defined(__ANDROID__)
  3. מקבלים את הכיתה firebase::auth::Auth ל-firebase::App. יש מיפוי אחד-לאחד בין App לבין Auth.
    firebase::auth::Auth* auth = firebase::auth::Auth::GetAuth(app);

טיפול בתהליך הכניסה באמצעות Firebase SDK

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

בפלטפורמות של Apple

אימות המשתמשים באמצעות Firebase דרך ה-SDK של Objective-C ל-Apple Sign In, שמופעל מקוד ה-C++.

  1. לכל בקשת כניסה צריך ליצור מחרוזת אקראית – "nonce" – שבו תשתמשו כדי לוודא שהאסימון המזהה שקיבלתם מוענקת במיוחד בתגובה לבקשת האימות של האפליקציה. השלב הזה חשוב כדי למנוע התקפות שליחה מחדש.

      - (NSString *)randomNonce:(NSInteger)length {
        NSAssert(length > 0, @"Expected nonce to have positive length");
        NSString *characterSet = @"0123456789ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvwxyz-._";
        NSMutableString *result = [NSMutableString string];
        NSInteger remainingLength = length;
    
        while (remainingLength > 0) {
          NSMutableArray *randoms = [NSMutableArray arrayWithCapacity:16];
          for (NSInteger i = 0; i < 16; i++) {
            uint8_t random = 0;
            int errorCode = SecRandomCopyBytes(kSecRandomDefault, 1, &random);
            NSAssert(errorCode == errSecSuccess, @"Unable to generate nonce: OSStatus %i", errorCode);
    
            [randoms addObject:@(random)];
          }
    
          for (NSNumber *random in randoms) {
            if (remainingLength == 0) {
              break;
            }
    
            if (random.unsignedIntValue < characterSet.length) {
              unichar character = [characterSet characterAtIndex:random.unsignedIntValue];
              [result appendFormat:@"%C", character];
              remainingLength--;
            }
          }
        }
      }
    
    

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

  2. מתחילים את תהליך הכניסה של Apple, ומצרפים לבקשה את הגיבוב (hash) של המזהה החד-פעמי (nonce) לפי SHA256 ואת סוג הנציג (delegate) שיטפל בתשובה של Apple (ראו את השלב הבא):

      - (void)startSignInWithAppleFlow {
        NSString *nonce = [self randomNonce:32];
        self.currentNonce = nonce;
        ASAuthorizationAppleIDProvider *appleIDProvider = [[ASAuthorizationAppleIDProvider alloc] init];
        ASAuthorizationAppleIDRequest *request = [appleIDProvider createRequest];
        request.requestedScopes = @[ASAuthorizationScopeFullName, ASAuthorizationScopeEmail];
        request.nonce = [self stringBySha256HashingString:nonce];
    
        ASAuthorizationController *authorizationController =
            [[ASAuthorizationController alloc] initWithAuthorizationRequests:@[request]];
        authorizationController.delegate = self;
        authorizationController.presentationContextProvider = self;
        [authorizationController performRequests];
      }
    
      - (NSString *)stringBySha256HashingString:(NSString *)input {
        const char *string = [input UTF8String];
        unsigned char result[CC_SHA256_DIGEST_LENGTH];
        CC_SHA256(string, (CC_LONG)strlen(string), result);
    
        NSMutableString *hashed = [NSMutableString stringWithCapacity:CC_SHA256_DIGEST_LENGTH * 2];
        for (NSInteger i = 0; i < CC_SHA256_DIGEST_LENGTH; i++) {
          [hashed appendFormat:@"%02x", result[i]];
        }
        return hashed;
      }
    
  3. מטפלים בתגובה של Apple בהטמעה של 'ASAuthorizationControllerDelegate'. אם הכניסה בוצעה בהצלחה, משתמשים באסימון המזהה מהתגובה של Apple עם ה-nonce ללא גיבוב כדי לבצע אימות באמצעות Firebase:

      - (void)authorizationController:(ASAuthorizationController *)controller
         didCompleteWithAuthorization:(ASAuthorization *)authorization API_AVAILABLE(ios(13.0)) {
        if ([authorization.credential isKindOfClass:[ASAuthorizationAppleIDCredential class]]) {
          ASAuthorizationAppleIDCredential *appleIDCredential = authorization.credential;
          NSString *rawNonce = self.currentNonce;
          NSAssert(rawNonce != nil, @"Invalid state: A login callback was received, but no login request was sent.");
    
          if (appleIDCredential.identityToken == nil) {
            NSLog(@"Unable to fetch identity token.");
            return;
          }
    
          NSString *idToken = [[NSString alloc] initWithData:appleIDCredential.identityToken
                                                    encoding:NSUTF8StringEncoding];
          if (idToken == nil) {
            NSLog(@"Unable to serialize id token from data: %@", appleIDCredential.identityToken);
          }
        }
    
  4. משתמשים במחרוזת האסימון שמתקבלת ובצופן הצופן המקורי כדי ליצור Firebase פרטי כניסה וכניסה ל-Firebase.

    firebase::auth::OAuthProvider::GetCredential(
            /*provider_id=*/"apple.com", token, nonce,
            /*access_token=*/nullptr);
    
    firebase::Future<firebase::auth::AuthResult> result =
        auth->SignInAndRetrieveDataWithCredential(credential);
    
  5. אפשר להשתמש באותו קו ביטול נעילה יחד עם Reauthenticate, שיכול להיות משמש לאחזור פרטי כניסה חדשים לפעולות רגישות שמצריכות ההתחברות האחרונה.

    firebase::Future<firebase::auth::AuthResult> result =
        user->Reauthenticate(credential);
    
  6. אפשר להשתמש באותו דפוס כדי לקשר חשבון באמצעות 'כניסה באמצעות חשבון Apple'. עם זאת, יכול להיות שתופיע שגיאה אם חשבון Firebase קיים כבר מקושר לחשבון Apple שאתם מנסים לקשר אליו. במקרה כזה, העתיד יחזיר סטטוס של kAuthErrorCredentialAlreadyInUse ויכול להיות שה-AuthResult יכיל credential תקין. אפשר להשתמש בפרטי הכניסה האלה כדי להיכנס לחשבון המקושר ל-Apple דרך SignInAndRetrieveDataWithCredential, בלי צורך ליצור אסימון חד-פעמי נוסף להתחברות ל-Apple.

    firebase::Future<firebase::auth::AuthResult> link_result =
        auth->current_user().LinkWithCredential(credential);
    
    // To keep example simple, wait on the current thread until call completes.
    while (link_result.status() == firebase::kFutureStatusPending) {
      Wait(100);
    }
    
    // Determine the result of the link attempt
    if (link_result.error() == firebase::auth::kAuthErrorNone) {
      // user linked correctly.
    } else if (link_result.error() ==
                   firebase::auth::kAuthErrorCredentialAlreadyInUse &&
               link_result.result()
                   ->additional_user_info.updated_credential.is_valid()) {
      // Sign In with the new credential
      firebase::Future<firebase::auth::AuthResult> result =
          auth->SignInAndRetrieveDataWithCredential(
              link_result.result()->additional_user_info.updated_credential);
    } else {
      // Another link error occurred.
    }

ב-Android

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

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

  1. יוצרים מופע של FederatedOAuthProviderData שמוגדר עם מזהה הספק המתאים ל-Apple.

    firebase::auth::FederatedOAuthProviderData provider_data("apple.com");
    
  2. אופציונלי: מציינים היקפי הרשאות OAuth 2.0 נוספים מעבר לברירת המחדל שאתם מגדירים שרוצים לבקש מספק האימות.

    provider_data.scopes.push_back("email");
    provider_data.scopes.push_back("name");
    
  3. אופציונלי: אם רוצים להציג את מסך הכניסה של Apple בשפה שאינה אנגלית, מגדירים את הפרמטר locale. כאן מפורטות האזורים הנתמכים להתחברות באמצעות חשבון Apple.

    // Localize to French.
    provider_data.custom_parameters["language"] = "fr";
    ```
    
  4. אחרי שהגדרתם את נתוני הספק, השתמשו בהם כדי ליצור FedeatedOAuthProvider.

    // Construct a FederatedOAuthProvider for use in Auth methods.
    firebase::auth::FederatedOAuthProvider provider(provider_data);
    
  5. מבצעים אימות עם Firebase באמצעות אובייקט של ספק האימות. שימו לב שבניגוד ל- פעולות אחרות של FirebaseAuth – הן יכולות לשלוט בממשק המשתמש שלכם על ידי הקפצה תצוגת אינטרנט שבה המשתמש יכול להזין את פרטי הכניסה שלו.

    כדי להתחיל את תהליך הכניסה, צריך לבצע קריאה ל-signInWithProvider:

    firebase::Future<firebase::auth::AuthResult> result =
      auth->SignInWithProvider(provider_data);
    

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

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

    firebase::Future<firebase::auth::AuthResult> result =
      user.ReauthenticateWithProvider(provider_data);
    

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

  7. אפשר גם להשתמש ב-LinkWithCredential() כדי לקשר ספקי זהויות שונים לחשבונות קיימים.

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

    לדוגמה, כדי לקשר חשבון Facebook לחשבון Firebase הנוכחי, משתמשים ב- אסימון הגישה שקיבלתם מכניסת המשתמש ל-Facebook:

    // Initialize a Facebook credential with a Facebook access token.
    AuthCredential credential =
        firebase::auth::FacebookAuthProvider.getCredential(token);
    
    // Assuming the current user is an Apple user linking a Facebook provider.
    firebase::Future<firebase::auth::AuthResult> result =
        auth.current_user().LinkWithCredential(credential);
    

כניסה באמצעות Apple Notes

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

כמו כן, כשהמשתמש בוחר שלא לשתף את כתובת האימייל שלו עם האפליקציה, Apple מקצה כתובת אימייל ייחודית לאותו משתמש (בטופס xyz@privaterelay.appleid.com), שאותו הוא משתף עם האפליקציה. אם מוגדר שירות ממסר האימייל הפרטי, Apple מעבירה אימיילים שנשלחים אל את הכתובת האנונימית לכתובת האימייל האמיתית של המשתמש.

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

השלבים הבאים

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

באפליקציות שלכם, תוכלו לקבל את פרטי הפרופיל הבסיסיים של המשתמש דרך אובייקט firebase::auth::User. צפייה ניהול משתמשים.

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