Google is committed to advancing racial equity for Black communities. See how.
דף זה תורגם על ידי Cloud Translation API.
Switch to English

אמת באמצעות אפל ב- iOS

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

לפני שאתה מתחיל

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

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

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

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

  1. אפשר כניסה עם Apple עבור האפליקציה שלך בדף אישורים, מזהים ופרופילים באתר המפתחים של אפל.
  2. אם אתה משתמש באחת מתכונות האימות של Firebase ששולחות דוא"ל למשתמשים, כולל כניסה לקישור דוא"ל, אימות כתובת דוא"ל, ביטול שינוי חשבון ואחרים, הגדר את שירות ממסר הדוא"ל הפרטי של Apple noreply@ YOUR_FIREBASE_PROJECT_ID .firebaseapp.com (או תחום תבנית הדוא"ל המותאם אישית שלך) כדי שאפל תוכל להעביר דוא"ל שנשלח על ידי Firebase Authentication לכתובות דוא"ל של Apple אנונימיות.

אפשר את אפל כספקית כניסה

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

ציית לדרישות הנתונים האנונימיות של Apple

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

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

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

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

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

כדי לבצע אימות עם חשבון Apple, התחבר תחילה למשתמש לחשבון Apple שלו באמצעות מסגרת AuthenticationServices של אפל, ולאחר מכן השתמש באסימון הזיהוי מתגובת אפל ליצירת אובייקט AuthCredential Firebase:

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

    באפשרותך ליצור SecRandomCopyBytes(_:_:_) מאובטח בהצפנה ב- iOS באמצעות SecRandomCopyBytes(_:_:_) , כמו בדוגמה הבאה:

    מָהִיר

    // Adapted from https://auth0.com/docs/api-auth/tutorials/nonce#generate-a-cryptographically-random-nonce
    private func randomNonceString(length: Int = 32) -> String {
      precondition(length > 0)
      let charset: Array<Character> =
          Array("0123456789ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvwxyz-._")
      var result = ""
      var remainingLength = length
    
      while remainingLength > 0 {
        let randoms: [UInt8] = (0 ..< 16).map { _ in
          var random: UInt8 = 0
          let errorCode = SecRandomCopyBytes(kSecRandomDefault, 1, &random)
          if errorCode != errSecSuccess {
            fatalError("Unable to generate nonce. SecRandomCopyBytes failed with OSStatus \(errorCode)")
          }
          return random
        }
    
        randoms.forEach { random in
          if remainingLength == 0 {
            return
          }
    
          if random < charset.count {
            result.append(charset[Int(random)])
            remainingLength -= 1
          }
        }
      }
    
      return result
    }
    

    מטרה-ג

    - (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--;
          }
        }
      }
    
      return result;
    }
    

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

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

    מָהִיר

    import CryptoKit
    
    // Unhashed nonce.
    fileprivate var currentNonce: String?
    
    @available(iOS 13, *)
    func startSignInWithAppleFlow() {
      let nonce = randomNonceString()
      currentNonce = nonce
      let appleIDProvider = ASAuthorizationAppleIDProvider()
      let request = appleIDProvider.createRequest()
      request.requestedScopes = [.fullName, .email]
      request.nonce = sha256(nonce)
    
      let authorizationController = ASAuthorizationController(authorizationRequests: [request])
      authorizationController.delegate = self
      authorizationController.presentationContextProvider = self
      authorizationController.performRequests()
    }
    
    @available(iOS 13, *)
    private func sha256(_ input: String) -> String {
      let inputData = Data(input.utf8)
      let hashedData = SHA256.hash(data: inputData)
      let hashString = hashedData.compactMap {
        return String(format: "%02x", $0)
      }.joined()
    
      return hashString
    }
    

    מטרה-ג

    @import CommonCrypto;
    
    - (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. לטפל בתגובה של אפל ביישום ASAuthorizationControllerDelegate . אם הכניסה הצליחה, השתמש באסימון הזיהוי מהתגובה של אפל עם ה- nonce שלא נפגע כדי לאמת עם Firebase:

    מָהִיר

    @available(iOS 13.0, *)
    extension MainViewController: ASAuthorizationControllerDelegate {
    
      func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) {
        if let appleIDCredential = authorization.credential as? ASAuthorizationAppleIDCredential {
          guard let nonce = currentNonce else {
            fatalError("Invalid state: A login callback was received, but no login request was sent.")
          }
          guard let appleIDToken = appleIDCredential.identityToken else {
            print("Unable to fetch identity token")
            return
          }
          guard let idTokenString = String(data: appleIDToken, encoding: .utf8) else {
            print("Unable to serialize token string from data: \(appleIDToken.debugDescription)")
            return
          }
          // Initialize a Firebase credential.
          let credential = OAuthProvider.credential(withProviderID: "apple.com",
                                                    IDToken: idTokenString,
                                                    rawNonce: nonce)
          // Sign in with Firebase.
          Auth.auth().signIn(with: credential) { (authResult, error) in
            if error {
              // Error. If error.code == .MissingOrInvalidNonce, make sure
              // you're sending the SHA256-hashed nonce as a hex string with
              // your request to Apple.
              print(error.localizedDescription)
              return
            }
            // User is signed in to Firebase with Apple.
            // ...
          }
        }
      }
    
      func authorizationController(controller: ASAuthorizationController, didCompleteWithError error: Error) {
        // Handle error.
        print("Sign in with Apple errored: \(error)")
      }
    
    }
    

    מטרה-ג

    - (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);
        }
    
        // Initialize a Firebase credential.
        FIROAuthCredential *credential = [FIROAuthProvider credentialWithProviderID:@"apple.com"
                                                                            IDToken:idToken
                                                                           rawNonce:rawNonce];
    
        // Sign in with Firebase.
        [[FIRAuth auth] signInWithCredential:credential
                                  completion:^(FIRAuthDataResult * _Nullable authResult,
                                               NSError * _Nullable error) {
          if (error != nil) {
            // Error. If error.code == FIRAuthErrorCodeMissingOrInvalidNonce,
            // make sure you're sending the SHA256-hashed nonce as a hex string
            // with your request to Apple.
            return;
          }
          // Sign-in succeeded!
        }];
      }
    }
    
    - (void)authorizationController:(ASAuthorizationController *)controller
               didCompleteWithError:(NSError *)error API_AVAILABLE(ios(13.0)) {
      NSLog(@"Sign in with Apple errored: %@", error);
    }
    

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

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

Apple משתפת פרטי משתמש, כגון שם התצוגה, רק עם אפליקציות בפעם הראשונה שמשתמש נכנס. בדרך כלל Firebase שומרת את שם התצוגה בפעם הראשונה שמשתמש נכנס עם Apple, שתוכל להשיג באמצעות Auth.auth().currentUser.displayName . עם זאת, אם בעבר השתמשת באפל כדי להיכנס למשתמש לאפליקציה מבלי להשתמש ב- Firebase, אפל לא תספק ל- Firebase את שם התצוגה של המשתמש.

אימות מחדש וקישור חשבונות

ניתן להשתמש באותה תבנית עם reauthenticateWithCredential() , בה תוכלו להשתמש בכדי לאחזר אישורים חדשים לפעולות רגישות הדורשות כניסה לאחרונה:

מָהִיר

// Initialize a fresh Apple credential with Firebase.
let credential = OAuthProvider.credential(
  withProviderID: "apple.com",
  IDToken: appleIdToken,
  rawNonce: rawNonce
)
// Reauthenticate current Apple user with fresh Apple credential.
Auth.auth().currentUser.reauthenticate(with: credential) { (authResult, error) in
  guard error != nil else { return }
  // Apple user successfully re-authenticated.
  // ...
}

מטרה-ג

FIRAuthCredential *credential = [FIROAuthProvider credentialWithProviderID:@"apple.com",
                                                                   IDToken:appleIdToken,
                                                                  rawNonce:rawNonce];
[[FIRAuth auth].currentUser
    reauthenticateWithCredential:credential
                      completion:^(FIRAuthDataResult * _Nullable authResult,
                                   NSError * _Nullable error) {
  if (error) {
    // Handle error.
  }
  // Apple user successfully re-authenticated.
  // ...
}];

בנוסף, תוכלו להשתמש ב- linkWithCredential() כדי לקשר ספקי זהות שונים לחשבונות קיימים.

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

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

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

מָהִיר

// Initialize a Facebook credential with Firebase.
let credential = FacebookAuthProvider.credential(
  withAccessToken: AccessToken.current!.tokenString
)
// Assuming the current user is an Apple user linking a Facebook provider.
Auth.auth().currentUser.link(with: credential) { (authResult, error) in
  // Facebook credential is linked to the current Apple user.
  // The user can now sign in with Facebook or Apple to the same Firebase
  // account.
  // ...
}

מטרה-ג

// Initialize a Facebook credential with Firebase.
FacebookAuthCredential *credential = [FIRFacebookAuthProvider credentialWithAccessToken:accessToken];
// Assuming the current user is an Apple user linking a Facebook provider.
[FIRAuth.auth linkWithCredential:credential completion:^(FIRAuthDataResult * _Nullable authResult, NSError * _Nullable error) {
  // Facebook credential is linked to the current Apple user.
  // The user can now sign in with Facebook or Apple to the same Firebase
  // account.
  // ...
}];

הצעדים הבאים

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

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

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

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

כדי לצאת ממשתמש, התקשר signOut: .

מָהִיר

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

מטרה-ג

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

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