Melakukan Autentikasi Menggunakan Login dengan Google di iOS

Anda dapat mengizinkan pengguna untuk melakukan autentikasi dengan Firebase menggunakan Akun Google miliknya dengan mengintegrasikan Login dengan Google ke dalam aplikasi Anda.

Sebelum memulai

  1. Tambahkan Firebase ke project iOS Anda. Sertakan pod berikut di Podfile:
    pod 'Firebase/Auth'
    pod 'GoogleSignIn'
    
  2. Jika Anda belum menghubungkan aplikasi ke project Firebase, lakukanlah dari Firebase console.
  3. Aktifkan Login dengan Google di Firebase console:
    1. Di Firebase console, buka bagian Auth.
    2. Di tab Metode login, aktifkan metode login dengan Google lalu klik Simpan.

1. Mengimpor file header yang dibutuhkan

Pertama, Anda harus mengimpor file header Firebase SDK dan Google Sign-In SDK ke dalam aplikasi.

Swift

Dalam delegasi aplikasi, impor file header berikut:

import Firebase
import GoogleSignIn

Dalam pengontrol tampilan login, impor file header berikut:

import Firebase
import GoogleSignIn

Objective-C

Dalam delegasi aplikasi, impor file header berikut:

@import Firebase;
@import GoogleSignIn;

Dalam pengontrol tampilan login, impor file header berikut:

@import Firebase;
@import GoogleSignIn;

2. Mengimplementasikan Login dengan Google

Implementasikan Login dengan Google dengan mengikuti langkah-langkah berikut. Lihat dokumentasi developer Login dengan Google untuk mengetahui detail penggunaan Login dengan Google pada iOS.

  1. Tambahkan skema URL khusus ke project Xcode Anda:
    1. Buka konfigurasi project, klik 2 kali pada nama project di tampilan struktur pohon sebelah kiri. Pilih aplikasi Anda dari bagian TARGET, lalu pilih tab Info, serta perluas bagian Jenis URL.
    2. Klik tombol +, lalu tambahkan skema URL untuk client ID terbalik Anda. Untuk menemukan nilai ini, buka file konfigurasi GoogleService-Info.plist, lalu cari kunci REVERSED_CLIENT_ID. Salin nilai kunci tersebut, lalu tempel ke dalam kotak Skema URL pada halaman konfigurasi. Biarkan kolom lainnya kosong.

      Jika sudah selesai, konfigurasi akan terlihat seperti berikut (tetapi dengan nilai khusus aplikasi Anda):

  2. Deklarasikan bahwa delegasi aplikasi mengimplementasikan protokol GIDSignInDelegate.

    Swift

    Di AppDelegate.swift:
    class AppDelegate: UIResponder, UIApplicationDelegate, GIDSignInDelegate {
    

    Objective-C

    Di AppDelegate.h:
    @interface AppDelegate : UIResponder<UIApplicationDelegate, GIDSignInDelegate>
    
  3. Dalam metode application:didFinishLaunchingWithOptions: delegasi aplikasi Anda, konfigurasikan objek FirebaseApp dan setel delegasi login.

    Swift

    // Use Firebase library to configure APIs
    FirebaseApp.configure()
    
    GIDSignIn.sharedInstance().clientID = FirebaseApp.app()?.options.clientID
    GIDSignIn.sharedInstance().delegate = self
    

    Objective-C

    // Use Firebase library to configure APIs
    [FIRApp configure];
    
    [GIDSignIn sharedInstance].clientID = [FIRApp defaultApp].options.clientID;
    [GIDSignIn sharedInstance].delegate = self;
    
  4. Implementasikan metode application:openURL:options: dari delegasi aplikasi Anda. Metode tersebut harus memanggil metode handleURL pada instance GIDSignIn, yang akan menangani URL yang diterima aplikasi Anda dengan benar di akhir proses autentikasi.

    Swift

    @available(iOS 9.0, *)
    func application(_ application: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any])
      -> Bool {
      return GIDSignIn.sharedInstance().handle(url)
    }
    

    Objective-C

    - (BOOL)application:(nonnull UIApplication *)application
                openURL:(nonnull NSURL *)url
                options:(nonnull NSDictionary<NSString *, id> *)options {
      return [[GIDSignIn sharedInstance] handleURL:url];
    }
    

    Agar aplikasi Anda berjalan di iOS 8 dan versi sebelumnya, implementasikan juga metode application:openURL:sourceApplication:annotation: yang sudah tidak digunakan lagi.

    Swift

    func application(_ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any) -> Bool {
        return GIDSignIn.sharedInstance().handle(url)
    }
    

    Objective-C

    - (BOOL)application:(UIApplication *)application
                openURL:(NSURL *)url
      sourceApplication:(NSString *)sourceApplication
             annotation:(id)annotation {
      return [[GIDSignIn sharedInstance] handleURL:url];
    }
    
  5. Pada delegasi aplikasi, implementasikan protokol GIDSignInDelegate untuk menangani proses login dengan menetapkan metode berikut:

    Objective-C

    - (void)signIn:(GIDSignIn *)signIn
    didSignInForUser:(GIDGoogleUser *)user
         withError:(NSError *)error {
      // ...
      if (error == nil) {
        GIDAuthentication *authentication = user.authentication;
        FIRAuthCredential *credential =
        [FIRGoogleAuthProvider credentialWithIDToken:authentication.idToken
                                         accessToken:authentication.accessToken];
        // ...
      } else {
        // ...
      }
    }
    
    - (void)signIn:(GIDSignIn *)signIn
    didDisconnectWithUser:(GIDGoogleUser *)user
         withError:(NSError *)error {
      // Perform any operations when the user disconnects from app here.
      // ...
    }
    

    Swift

    func sign(_ signIn: GIDSignIn!, didSignInFor user: GIDGoogleUser!, withError error: Error?) {
      // ...
      if let error = error {
        // ...
        return
      }
    
      guard let authentication = user.authentication else { return }
      let credential = GoogleAuthProvider.credential(withIDToken: authentication.idToken,
                                                        accessToken: authentication.accessToken)
      // ...
    }
    
    func sign(_ signIn: GIDSignIn!, didDisconnectWith user: GIDGoogleUser!, withError error: Error!) {
        // Perform any operations when the user disconnects from app here.
        // ...
    }
    
  6. Dalam pengontrol tampilan, ganti metode viewDidLoad untuk menetapkan pengontrol tampilan presenter objek GIDSignIn, dan (opsional) untuk login secara diam-diam jika memungkinkan.

    Objective-C

    [GIDSignIn sharedInstance].presentingViewController = self;
    [[GIDSignIn sharedInstance] signIn];
    

    Swift

    GIDSignIn.sharedInstance()?.presentingViewController = self
    GIDSignIn.sharedInstance().signIn()
    
  7. Tambahkan GIDSignInButton ke storyboard, file XIB, atau buat instance secara terprogram. Untuk menambahkan tombol ke storyboard atau file XIB, tambahkan Tampilan dan setel kelas khususnya ke GIDSignInButton.
  8. Opsional: Jika Anda ingin menyesuaikan tombol, lakukan hal berikut:

    Swift

    1. Di pengontrol tampilan, deklarasikan tombol login sebagai properti.
      @IBOutlet weak var signInButton: GIDSignInButton!
    2. Hubungkan tombol ke properti signInButton yang baru saja Anda deklarasikan.
    3. Sesuaikan tombol dengan menyetel properti objek GIDSignInButton.

    Objective-C

    1. Dalam file header pengontrol tampilan, deklarasikan tombol login sebagai properti.
      @property(weak, nonatomic) IBOutlet GIDSignInButton *signInButton;
    2. Hubungkan tombol ke properti signInButton yang baru saja Anda deklarasikan.
    3. Sesuaikan tombol dengan menyetel properti objek GIDSignInButton.

3. Mengautentikasi dengan Firebase

Pada metode signIn:didSignInForUser:withError:, dapatkan token ID Google dan token akses Google dari objek GIDAuthentication lalu tukarkan dengan kredensial Firebase:

Swift

func sign(_ signIn: GIDSignIn!, didSignInFor user: GIDGoogleUser!, withError error: Error?) {
  // ...
  if let error = error {
    // ...
    return
  }

  guard let authentication = user.authentication else { return }
  let credential = GoogleAuthProvider.credential(withIDToken: authentication.idToken,
                                                    accessToken: authentication.accessToken)
  // ...
}

Objective-C

- (void)signIn:(GIDSignIn *)signIn
didSignInForUser:(GIDGoogleUser *)user
     withError:(NSError *)error {
  // ...
  if (error == nil) {
    GIDAuthentication *authentication = user.authentication;
    FIRAuthCredential *credential =
    [FIRGoogleAuthProvider credentialWithIDToken:authentication.idToken
                                     accessToken:authentication.accessToken];
    // ...
  } else {
    // ...
  }
}

Terakhir, lakukan autentikasi dengan Firebase menggunakan kredensial:

Swift

Auth.auth().signIn(with: credential) { (authResult, error) in
  if let error = error {
    let authError = error as NSError
    if (isMFAEnabled && authError.code == AuthErrorCode.secondFactorRequired.rawValue) {
      // The user is a multi-factor user. Second factor challenge is required.
      let resolver = authError.userInfo[AuthErrorUserInfoMultiFactorResolverKey] as! MultiFactorResolver
      var displayNameString = ""
      for tmpFactorInfo in (resolver.hints) {
        displayNameString += tmpFactorInfo.displayName ?? ""
        displayNameString += " "
      }
      self.showTextInputPrompt(withMessage: "Select factor to sign in\n\(displayNameString)", completionBlock: { userPressedOK, displayName in
        var selectedHint: PhoneMultiFactorInfo?
        for tmpFactorInfo in resolver.hints {
          if (displayName == tmpFactorInfo.displayName) {
            selectedHint = tmpFactorInfo as? PhoneMultiFactorInfo
          }
        }
        PhoneAuthProvider.provider().verifyPhoneNumber(with: selectedHint!, uiDelegate: nil, multiFactorSession: resolver.session) { verificationID, error in
          if error != nil {
            print("Multi factor start sign in failed. Error: \(error.debugDescription)")
          } else {
            self.showTextInputPrompt(withMessage: "Verification code for \(selectedHint?.displayName ?? "")", completionBlock: { userPressedOK, verificationCode in
              let credential: PhoneAuthCredential? = PhoneAuthProvider.provider().credential(withVerificationID: verificationID!, verificationCode: verificationCode!)
              let assertion: MultiFactorAssertion? = PhoneMultiFactorGenerator.assertion(with: credential!)
              resolver.resolveSignIn(with: assertion!) { authResult, error in
                if error != nil {
                  print("Multi factor finanlize sign in failed. Error: \(error.debugDescription)")
                } else {
                  self.navigationController?.popViewController(animated: true)
                }
              }
            })
          }
        }
      })
    } else {
      self.showMessagePrompt(error.localizedDescription)
      return
    }
    // ...
    return
  }
  // User is signed in
  // ...
}

Objective-C

[[FIRAuth auth] signInWithCredential:credential
                          completion:^(FIRAuthDataResult * _Nullable authResult,
                                       NSError * _Nullable error) {
    if (isMFAEnabled && error && error.code == FIRAuthErrorCodeSecondFactorRequired) {
      FIRMultiFactorResolver *resolver = error.userInfo[FIRAuthErrorUserInfoMultiFactorResolverKey];
      NSMutableString *displayNameString = [NSMutableString string];
      for (FIRMultiFactorInfo *tmpFactorInfo in resolver.hints) {
        [displayNameString appendString:tmpFactorInfo.displayName];
        [displayNameString appendString:@" "];
      }
      [self showTextInputPromptWithMessage:[NSString stringWithFormat:@"Select factor to sign in\n%@", displayNameString]
                           completionBlock:^(BOOL userPressedOK, NSString *_Nullable displayName) {
       FIRPhoneMultiFactorInfo* selectedHint;
       for (FIRMultiFactorInfo *tmpFactorInfo in resolver.hints) {
         if ([displayName isEqualToString:tmpFactorInfo.displayName]) {
           selectedHint = (FIRPhoneMultiFactorInfo *)tmpFactorInfo;
         }
       }
       [FIRPhoneAuthProvider.provider
        verifyPhoneNumberWithMultiFactorInfo:selectedHint
        UIDelegate:nil
        multiFactorSession:resolver.session
        completion:^(NSString * _Nullable verificationID, NSError * _Nullable error) {
          if (error) {
            [self showMessagePrompt:error.localizedDescription];
          } else {
            [self showTextInputPromptWithMessage:[NSString stringWithFormat:@"Verification code for %@", selectedHint.displayName]
                                 completionBlock:^(BOOL userPressedOK, NSString *_Nullable verificationCode) {
             FIRPhoneAuthCredential *credential =
                 [[FIRPhoneAuthProvider provider] credentialWithVerificationID:verificationID
                                                              verificationCode:verificationCode];
             FIRMultiFactorAssertion *assertion = [FIRPhoneMultiFactorGenerator assertionWithCredential:credential];
             [resolver resolveSignInWithAssertion:assertion completion:^(FIRAuthDataResult * _Nullable authResult, NSError * _Nullable error) {
               if (error) {
                 [self showMessagePrompt:error.localizedDescription];
               } else {
                 NSLog(@"Multi factor finanlize sign in succeeded.");
               }
             }];
           }];
          }
        }];
     }];
    }
  else if (error) {
    // ...
    return;
  }
  // User successfully signed in. Get user data from the FIRUser object
  if (authResult == nil) { return; }
  FIRUser *user = authResult.user;
  // ...
}];

Langkah berikutnya

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

  • Di aplikasi yang dimiliki, Anda bisa mendapatkan informasi profil dasar pengguna dari objek FIRUser. Baca bagian Mengelola Pengguna.

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

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

Agar pengguna logout, panggil 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;
}

Anda juga dapat menambahkan kode penanganan error untuk berbagai error autentikasi. Lihat Menangani Error.