Apple Kullanarak Kimlik Doğrulama

Uçtan uca OAuth 2.0 oturum açma akışını gerçekleştirmek için Firebase SDK'yı kullanarak kullanıcılarınızın Apple kimliklerini kullanarak Firebase ile kimlik doğrulaması yapmalarına olanak tanıyabilirsiniz.

Sen başlamadan önce

Apple'ı kullanarak kullanıcıların oturum açmasını sağlamak için öncelikle Apple'ın geliştirici sitesinde Apple ile Oturum Açma seçeneğini yapılandırın, ardından Firebase projeniz için oturum açma sağlayıcısı olarak Apple'ı etkinleştirin.

Apple Geliştirici Programına Katılın

Apple ile Oturum Açma yalnızca Apple Geliştirici Programı üyeleri tarafından yapılandırılabilir.

Apple ile Oturum Açmayı Yapılandırma

  1. Apple'ın geliştirici sitesinin Sertifikalar, Tanımlayıcılar ve Profiller sayfasında uygulamanız için Apple ile Oturum Açmayı etkinleştirin.
  2. Web için Apple ile Oturum Açmayı Yapılandırma bölümünün ilk bölümünde açıklandığı gibi web sitenizi uygulamanızla ilişkilendirin. İstendiğinde, aşağıdaki URL'yi Dönüş URL'si olarak kaydedin:
    https://YOUR_FIREBASE_PROJECT_ID.firebaseapp.com/__/auth/handler
    Firebase proje kimliğinizi Firebase konsol ayarları sayfasından alabilirsiniz. İşiniz bittiğinde, bir sonraki bölümde ihtiyaç duyacağınız yeni Hizmet Kimliğinizi not edin.
  3. Apple özel anahtarıyla Oturum Açma oluşturun . Bir sonraki bölümde yeni özel anahtarınıza ve anahtar kimliğinize ihtiyacınız olacak.
  4. E-posta bağlantısıyla oturum açma, e-posta adresi doğrulama, hesap değişikliği iptali ve diğerleri dahil olmak üzere kullanıcılara e-posta gönderen Firebase Authentication özelliklerinden herhangi birini kullanıyorsanız, Apple özel e-posta aktarma hizmetini yapılandırın ve noreply@ YOUR_FIREBASE_PROJECT_ID .firebaseapp.com kaydedin (veya özelleştirilmiş e-posta şablonu etki alanınız) böylece Apple, Firebase Authentication tarafından gönderilen e-postaları anonimleştirilmiş Apple e-posta adreslerine aktarabilir.

Apple'ı oturum açma sağlayıcısı olarak etkinleştirme

  1. Firebase'i Apple projenize ekleyin . Uygulamanızı Firebase konsolunda ayarlarken uygulamanızın paket kimliğini kaydettiğinizden emin olun.
  2. Firebase konsolunda Kimlik Doğrulama bölümünü açın. Oturum açma yöntemi sekmesinde Apple sağlayıcısını etkinleştirin. Önceki bölümde oluşturduğunuz Hizmet Kimliğini belirtin. Ayrıca OAuth kod akışı yapılandırması bölümünde Apple Ekip Kimliğinizi ve önceki bölümde oluşturduğunuz özel anahtarı ve anahtar kimliğini belirtin.

Apple'ın anonimleştirilmiş veri gereksinimlerine uyun

Apple ile Giriş Yap, kullanıcılara giriş yaparken e-posta adresleri de dahil olmak üzere verilerini anonimleştirme seçeneği sunar. Bu seçeneği seçen kullanıcıların, privaterelay.appleid.com etki alanına sahip e-posta adresleri vardır. Uygulamanızda Apple ile Giriş Yap'ı kullandığınızda, bu anonimleştirilmiş Apple Kimlikleriyle ilgili olarak Apple'ın geçerli geliştirici politikalarına veya şartlarına uymanız gerekir.

Bu, doğrudan tanımlayıcı herhangi bir kişisel bilgiyi anonimleştirilmiş bir Apple Kimliğiyle ilişkilendirmeden önce gerekli tüm kullanıcı onaylarının alınmasını içerir. Firebase Authentication'ı kullanırken bu, aşağıdaki eylemleri içerebilir:

  • Bir e-posta adresini anonimleştirilmiş bir Apple Kimliğine bağlayın veya tam tersi.
  • Bir telefon numarasını anonimleştirilmiş bir Apple Kimliğine veya tam tersine bağlayın
  • Anonim olmayan bir sosyal kimlik bilgisini (Facebook, Google vb.) anonimleştirilmiş bir Apple Kimliğine bağlayın veya tam tersi.

Yukarıdaki liste kapsamlı değildir. Uygulamanızın Apple'ın gereksinimlerini karşıladığından emin olmak için geliştirici hesabınızın Üyelik bölümündeki Apple Geliştirici Programı Lisans Sözleşmesine bakın.

Apple ile oturum açın ve Firebase ile kimlik doğrulaması yapın

Bir Apple hesabıyla kimlik doğrulaması yapmak için önce Apple'ın AuthenticationServices çerçevesini kullanarak kullanıcının Apple hesabında oturum açmasını sağlayın ve ardından bir Firebase AuthCredential nesnesi oluşturmak için Apple'ın yanıtındaki kimlik belirtecini kullanın:

  1. Her oturum açma isteği için, alacağınız kimlik belirtecinin uygulamanızın kimlik doğrulama isteğine yanıt olarak özel olarak verildiğinden emin olmak için kullanacağınız rastgele bir dize ("tek seferlik") oluşturun. Bu adım, tekrar saldırılarını önlemek için önemlidir.

    Aşağıdaki örnekte olduğu gibi SecRandomCopyBytes(_:_:_) ile kriptografik olarak güvenli bir nonce oluşturabilirsiniz:

    Süratli

    private func randomNonceString(length: Int = 32) -> String {
      precondition(length > 0)
      var randomBytes = [UInt8](repeating: 0, count: length)
      let errorCode = SecRandomCopyBytes(kSecRandomDefault, randomBytes.count, &randomBytes)
      if errorCode != errSecSuccess {
        fatalError(
          "Unable to generate nonce. SecRandomCopyBytes failed with OSStatus \(errorCode)"
        )
      }
    
      let charset: [Character] =
        Array("0123456789ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvwxyz-._")
    
      let nonce = randomBytes.map { byte in
        // Pick a random character from the set, wrapping around if needed.
        charset[Int(byte) % charset.count]
      }
    
      return String(nonce)
    }
    
        

    Amaç-C

    // Adapted from https://auth0.com/docs/api-auth/tutorials/nonce#generate-a-cryptographically-random-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--;
          }
        }
      }
    
      return [result copy];
    }
        

    Oturum açma isteğinizle birlikte nonce'ın SHA256 karmasını göndereceksiniz ve Apple bunu yanıtta değişmeden iletecektir. Firebase, orijinal nonce değerini karma hale getirerek ve bunu Apple tarafından iletilen değerle karşılaştırarak yanıtı doğrular.

    Süratli

    @available(iOS 13, *)
    private func sha256(_ input: String) -> String {
      let inputData = Data(input.utf8)
      let hashedData = SHA256.hash(data: inputData)
      let hashString = hashedData.compactMap {
        String(format: "%02x", $0)
      }.joined()
    
      return hashString
    }
    
        

    Amaç-C

    - (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;
    }
        
  2. İsteğinize, nonce'ın SHA256 karması ve Apple'ın yanıtını işleyecek temsilci sınıfı dahil olmak üzere Apple'ın oturum açma akışını başlatın (sonraki adıma bakın):

    Süratli

    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()
    }
    

    Amaç-C

    @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];
    }
    
  3. ASAuthorizationControllerDelegate uygulamanızda Apple'ın yanıtını ele alın. Oturum açma başarılıysa, Firebase ile kimlik doğrulaması yapmak için Apple'ın yanıtındaki kimlik belirtecini karma uygulanmamış nonce ile birlikte kullanın:

    Süratli

    @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, including the user's full name.
          let credential = OAuthProvider.appleCredential(withIDToken: idTokenString,
                                                            rawNonce: nonce,
                                                            fullName: appleIDCredential.fullName)
          // 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)")
      }
    
    }
    

    Amaç-C

    - (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, including the user's full name.
        FIROAuthCredential *credential = [FIROAuthProvider appleCredentialWithIDToken:IDToken
                                                                             rawNonce:self.appleRawNonce
                                                                             fullName:appleIDCredential.fullName];
    
        // 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 tarafından desteklenen diğer sağlayıcıların aksine Apple, fotoğraf URL'si sağlamaz.

Ayrıca, kullanıcı e-postasını uygulamayla paylaşmamayı seçtiğinde Apple, bu kullanıcı için uygulamanızla paylaştığı benzersiz bir e-posta adresini ( xyz@privaterelay.appleid.com biçiminde) sağlar. Özel e-posta aktarma hizmetini yapılandırdıysanız Apple, anonimleştirilmiş adrese gönderilen e-postaları kullanıcının gerçek e-posta adresine iletir.

Yeniden kimlik doğrulama ve hesap bağlama

Aynı model, yakın zamanda oturum açmayı gerektiren hassas işlemler için yeni bir kimlik bilgisi almak amacıyla kullanabileceğiniz reauthenticateWithCredential() ile de kullanılabilir:

Süratli

// 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.
  // ...
}

Amaç-C

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.
  // ...
}];

Ayrıca, farklı kimlik sağlayıcılarını mevcut hesaplara bağlamak için linkWithCredential() yöntemini kullanabilirsiniz.

Apple'ın, kullanıcıların Apple hesaplarını diğer verilere bağlamadan önce kullanıcıların açık iznini almanızı gerektirdiğini unutmayın.

Apple ile oturum açma, mevcut bir hesaba bağlanmak için kimlik doğrulama bilgilerini yeniden kullanmanıza izin vermez. Apple ile Giriş Yap kimlik bilgisini başka bir hesaba bağlamak istiyorsanız, öncelikle eski Apple ile Giriş Yap kimlik bilgisini kullanarak hesapları bağlamayı denemeli ve ardından yeni bir kimlik bilgisi bulmak için döndürülen hatayı incelemelisiniz. Yeni kimlik bilgisi, hatanın userInfo sözlüğünde bulunacaktır ve AuthErrorUserInfoUpdatedCredentialKey anahtarı aracılığıyla erişilebilir.

Örneğin, bir Facebook hesabını mevcut Firebase hesabına bağlamak için, kullanıcının Facebook'ta oturum açmasıyla elde ettiğiniz erişim jetonunu kullanın:

Süratli

// 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.
  // ...
}

Amaç-C

// 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.
  // ...
}];

Jeton iptali

Apple, hesap oluşturmayı destekleyen uygulamaların , App Store İnceleme Yönergeleri'nde açıklandığı gibi, kullanıcıların uygulama içinde hesaplarını silme işlemini başlatmasına izin vermesini şart koşuyor

Bu gereksinimi karşılamak için aşağıdaki adımları uygulayın:

  1. Apple ile Oturum Açma sağlayıcı yapılandırmasının Hizmet Kimliği ve OAuth kod akışı yapılandırması bölümünü, Apple ile Oturum Açmayı Yapılandırma bölümünde belirtildiği gibi doldurduğunuzdan emin olun.

  2. Firebase, Apple ile Giriş Yap ile kullanıcılar oluşturulduğunda kullanıcı jetonlarını saklamadığından, jetonlarını iptal edip hesabı silmeden önce kullanıcıdan tekrar oturum açmasını istemeniz gerekir.

    Süratli

    private func deleteCurrentUser() {
      do {
        let nonce = try CryptoUtils.randomNonceString()
        currentNonce = nonce
        let appleIDProvider = ASAuthorizationAppleIDProvider()
        let request = appleIDProvider.createRequest()
        request.requestedScopes = [.fullName, .email]
        request.nonce = CryptoUtils.sha256(nonce)
    
        let authorizationController = ASAuthorizationController(authorizationRequests: [request])
        authorizationController.delegate = self
        authorizationController.presentationContextProvider = self
        authorizationController.performRequests()
      } catch {
        // In the unlikely case that nonce generation fails, show error view.
        displayError(error)
      }
    }
    
    
  3. Yetkilendirme kodunu ASAuthorizationAppleIDCredential alın ve kullanıcının belirteçlerini iptal etmek için Auth.auth().revokeToken(withAuthorizationCode:) öğesini çağırmak için kullanın.

    Süratli

    func authorizationController(controller: ASAuthorizationController,
                                 didCompleteWithAuthorization authorization: ASAuthorization) {
      guard let appleIDCredential = authorization.credential as? ASAuthorizationAppleIDCredential
      else {
        print("Unable to retrieve AppleIDCredential")
        return
      }
    
      guard let _ = currentNonce else {
        fatalError("Invalid state: A login callback was received, but no login request was sent.")
      }
    
      guard let appleAuthCode = appleIDCredential.authorizationCode else {
        print("Unable to fetch authorization code")
        return
      }
    
      guard let authCodeString = String(data: appleAuthCode, encoding: .utf8) else {
        print("Unable to serialize auth code string from data: \(appleAuthCode.debugDescription)")
        return
      }
    
      Task {
        do {
          try await Auth.auth().revokeToken(withAuthorizationCode: authCodeString)
          try await user?.delete()
          self.updateUI()
        } catch {
          self.displayError(error)
        }
      }
    }
    
    
  4. Son olarak kullanıcı hesabını (ve ilişkili tüm verileri) silin

Sonraki adımlar

Bir kullanıcı ilk kez oturum açtıktan sonra, yeni bir kullanıcı hesabı oluşturulur ve kullanıcının oturum açtığı kimlik bilgileriyle (yani kullanıcı adı ve parolası, telefon numarası veya kimlik doğrulama sağlayıcı bilgileri) ilişkilendirilir. Bu yeni hesap, Firebase projenizin bir parçası olarak depolanır ve kullanıcının nasıl oturum açtığına bakılmaksızın projenizdeki her uygulamada bir kullanıcıyı tanımlamak için kullanılabilir.

  • Uygulamalarınızda kullanıcının temel profil bilgilerini User nesnesinden alabilirsiniz. Bkz . Kullanıcıları Yönetme .

  • Firebase Gerçek Zamanlı Veritabanı ve Bulut Depolama Güvenliği Kurallarınızda , oturum açan kullanıcının benzersiz kullanıcı kimliğini auth değişkeninden alabilir ve bunu, kullanıcının hangi verilere erişebileceğini kontrol etmek için kullanabilirsiniz.

Kimlik doğrulama sağlayıcısı kimlik bilgilerini mevcut bir kullanıcı hesabına bağlayarak kullanıcıların birden fazla kimlik doğrulama sağlayıcısı kullanarak uygulamanızda oturum açmasına izin verebilirsiniz.

Bir kullanıcının oturumunu kapatmak için signOut: öğesini çağırın.

Süratli

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

Amaç-C

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

Kimlik doğrulama hatalarının tamamı için hata işleme kodunu da eklemek isteyebilirsiniz. Bkz. Hataları İşleme .