Google berkomitmen untuk mendorong terwujudnya keadilan ras bagi komunitas Kulit Hitam. Lihat caranya.

Otentikasi Menggunakan Apple

Tetap teratur dengan koleksi Simpan dan kategorikan konten berdasarkan preferensi Anda.

Anda dapat mengizinkan pengguna melakukan autentikasi dengan Firebase menggunakan ID Apple mereka dengan menggunakan SDK Firebase untuk menjalankan alur masuk OAuth 2.0 menyeluruh.

Sebelum kamu memulai

Untuk masuk ke pengguna menggunakan Apple, pertama-tama konfigurasikan Masuk dengan Apple di situs pengembang Apple, lalu aktifkan Apple sebagai penyedia masuk untuk proyek Firebase Anda.

Bergabunglah dengan Program Pengembang Apple

Masuk dengan Apple hanya dapat dikonfigurasi oleh anggota Program Pengembang Apple .

Konfigurasi Masuk dengan Apple

  1. Aktifkan Masuk dengan Apple untuk aplikasi Anda di halaman Sertifikat, Pengidentifikasi & Profil di situs pengembang Apple.
  2. Jika Anda menggunakan salah satu fitur Firebase Authentication yang mengirim email ke pengguna, termasuk link masuk email, verifikasi alamat email, pencabutan perubahan akun, dan lainnya, konfigurasikan layanan relai email pribadi Apple dan daftarkan noreply@ YOUR_FIREBASE_PROJECT_ID .firebaseapp.com (atau domain template email khusus Anda) sehingga Apple dapat menyampaikan email yang dikirim oleh Firebase Authentication ke alamat email Apple yang dianonimkan.

Aktifkan Apple sebagai penyedia masuk

  1. Tambahkan Firebase ke proyek Apple Anda . Pastikan untuk mendaftarkan ID bundel aplikasi Anda saat menyiapkan aplikasi di Firebase console.
  2. Di Firebase console , buka bagian Auth . Pada tab Metode masuk , aktifkan penyedia Apple . Jika Anda hanya menggunakan Masuk dengan Apple di app, Anda dapat mengosongkan bidang ID Layanan, ID Tim Apple, kunci pribadi, dan ID kunci.

Patuhi persyaratan data anonim Apple

Masuk dengan Apple memberi pengguna opsi untuk menganonimkan data mereka, termasuk alamat email mereka, saat masuk. Pengguna yang memilih opsi ini memiliki alamat email dengan domain privaterelay.appleid.com . Saat Anda menggunakan Masuk dengan Apple di aplikasi Anda, Anda harus mematuhi kebijakan atau persyaratan pengembang yang berlaku dari Apple terkait ID Apple yang dianonimkan ini.

Ini termasuk memperoleh persetujuan pengguna yang diperlukan sebelum Anda mengaitkan informasi pribadi apa pun yang mengidentifikasi secara langsung dengan ID Apple yang dianonimkan. Saat menggunakan Firebase Authentication, tindakan ini dapat mencakup tindakan berikut:

  • Tautkan alamat email ke ID Apple yang dianonimkan atau sebaliknya.
  • Tautkan nomor telepon ke ID Apple yang dianonimkan atau sebaliknya
  • Tautkan kredensial sosial non-anonim (Facebook, Google, dll) ke ID Apple yang dianonimkan atau sebaliknya.

Daftar di atas tidak lengkap. Lihat Perjanjian Lisensi Program Pengembang Apple di bagian Keanggotaan akun pengembang Anda untuk memastikan aplikasi Anda memenuhi persyaratan Apple.

Masuk dengan Apple dan autentikasi dengan Firebase

Untuk mengautentikasi dengan akun Apple, pertama-tama masuklah pengguna ke akun Apple mereka menggunakan kerangka AuthenticationServices Apple , lalu gunakan token ID dari respons Apple untuk membuat objek Firebase AuthCredential :

  1. Untuk setiap permintaan masuk, buat string acak—"nonce"—yang akan Anda gunakan untuk memastikan token ID yang Anda dapatkan diberikan secara khusus sebagai tanggapan atas permintaan autentikasi aplikasi Anda. Langkah ini penting untuk mencegah serangan replay.

    Anda dapat membuat nonce yang aman secara kriptografis dengan SecRandomCopyBytes(_:_:_) , seperti pada contoh berikut:

    Cepat

    // 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: [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
    }
    
        

    Objective-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];
    }
        

    Anda akan mengirimkan hash SHA256 dari nonce dengan permintaan masuk Anda, yang akan diteruskan oleh Apple tanpa perubahan dalam tanggapannya. Firebase memvalidasi respons dengan hashing nonce asli dan membandingkannya dengan nilai yang diteruskan oleh Apple.

    Cepat

    @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
    }
    
        

    Objective-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. Mulai alur masuk Apple, termasuk dalam permintaan Anda hash SHA256 dari nonce dan kelas delegasi yang akan menangani respons Apple (lihat langkah berikutnya):

    Cepat

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

    Objective-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. Tangani respons Apple dalam implementasi ASAuthorizationControllerDelegate Anda. Jika proses masuk berhasil, gunakan token ID dari respons Apple dengan nonce tanpa hash untuk mengautentikasi dengan Firebase:

    Cepat

    @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)")
      }
    
    }
    

    Objective-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.
        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);
    }
    

Tidak seperti penyedia lain yang didukung oleh Firebase Auth, Apple tidak menyediakan URL foto.

Selain itu, saat pengguna memilih untuk tidak membagikan email mereka dengan aplikasi, Apple menyediakan alamat email unik untuk pengguna tersebut (dalam bentuk xyz@privaterelay.appleid.com ), yang dibagikan dengan aplikasi Anda. Jika Anda mengonfigurasi layanan relai email pribadi, Apple meneruskan email yang dikirim ke alamat anonim ke alamat email asli pengguna.

Apple hanya membagikan informasi pengguna seperti nama tampilan dengan aplikasi saat pertama kali pengguna masuk. Biasanya, Firebase menyimpan nama tampilan saat pertama kali pengguna masuk dengan Apple, yang bisa Anda dapatkan dengan Auth.auth().currentUser.displayName . Namun, jika sebelumnya Anda menggunakan Apple untuk memasukkan pengguna ke aplikasi tanpa menggunakan Firebase, Apple tidak akan memberikan nama tampilan pengguna kepada Firebase.

Otentikasi ulang dan penautan akun

Pola yang sama dapat digunakan dengan reauthenticateWithCredential() , yang dapat Anda gunakan untuk mengambil kredensial baru untuk operasi sensitif yang memerlukan proses masuk baru-baru ini:

Cepat

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

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

Dan, Anda dapat menggunakan linkWithCredential() untuk menautkan penyedia identitas yang berbeda ke akun yang ada.

Perhatikan bahwa Apple mengharuskan Anda untuk mendapatkan persetujuan eksplisit dari pengguna sebelum Anda menautkan akun Apple mereka ke data lain.

Masuk dengan Apple tidak akan mengizinkan Anda menggunakan kembali kredensial autentikasi untuk menautkan ke akun yang ada. Jika Anda ingin menautkan kredensial Masuk dengan Apple ke akun lain, Anda harus terlebih dahulu mencoba menautkan akun menggunakan kredensial Masuk dengan Apple yang lama, lalu memeriksa kesalahan yang dikembalikan untuk menemukan kredensial baru. Kredensial baru akan ditempatkan di kamus userInfo kesalahan dan dapat diakses melalui kunci FIRAuthErrorUserInfoUpdatedCredentialKey .

Misalnya, untuk menautkan akun Facebook ke akun Firebase saat ini, gunakan token akses yang Anda dapatkan dari memasukkan pengguna ke Facebook:

Cepat

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

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

Langkah selanjutnya

Setelah pengguna masuk untuk pertama kalinya, akun pengguna baru dibuat dan ditautkan ke kredensial—yaitu, nama pengguna dan sandi, nomor telepon, atau informasi penyedia autentikasi—yang digunakan pengguna untuk masuk. Akun baru ini disimpan sebagai bagian dari proyek Firebase Anda, dan dapat digunakan untuk mengidentifikasi pengguna di setiap aplikasi dalam proyek Anda, terlepas dari cara pengguna masuk.

  • Di aplikasi Anda, Anda bisa mendapatkan informasi profil dasar pengguna dari objek FIRUser . Lihat Kelola Pengguna .

  • Di Aturan Keamanan Firebase Realtime Database dan Cloud Storage , Anda bisa mendapatkan ID pengguna unik pengguna yang masuk dari variabel auth , dan menggunakannya untuk mengontrol data apa yang dapat diakses pengguna.

Anda dapat mengizinkan pengguna untuk masuk ke aplikasi Anda menggunakan beberapa penyedia autentikasi dengan menautkan kredensial penyedia autentikasi ke akun pengguna yang ada.

Untuk mengeluarkan pengguna, panggil signOut: .

Cepat

    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;
}

Anda mungkin juga ingin menambahkan kode penanganan kesalahan untuk berbagai kesalahan otentikasi. Lihat Menangani Kesalahan .