Google is committed to advancing racial equity for Black communities. See how.
本頁面由 Cloud Translation API 翻譯而成。
Switch to English

在iOS上使用Google登錄進行身份驗證

通過將Google登錄功能集成到您的應用中,您可以讓用戶使用其Google帳戶向Firebase進行身份驗證。

在你開始之前

  1. 將Firebase添加到您的iOS項目。在您的Podfile包含以下Pod:
    pod 'Firebase/Auth'
    pod 'GoogleSignIn'
    
  2. 如果您尚未將應用程序連接到Firebase項目,請從Firebase控制台進行
  3. 在Firebase控制台中啟用Google登錄:
    1. Firebase控制台中,打開“身份驗證”部分。
    2. 登錄方法標籤上,啟用Google登錄方法,然後點擊保存

1.導​​入所需的頭文件

首先,您必須將Firebase SDK和Google Sign-In SDK頭文件導入到您的應用中。

迅速

在您的應用程序委託中,導入以下頭文件:

import Firebase
import GoogleSignIn

在登錄視圖的視圖控制器中,導入以下頭文件:

import Firebase
import GoogleSignIn

目標C

在您的應用程序委託中,導入以下頭文件:

@import Firebase;
@import GoogleSignIn;

在登錄視圖的視圖控制器中,導入以下頭文件:

@import Firebase;
@import GoogleSignIn;

2.實施Google登錄

請按照以下步驟實施Google登錄。有關在iOS上使用Google登錄的詳細信息,請參閱Google登錄開發人員文檔

  1. 將自定義URL方案添加到您的Xcode項目中:
    1. 打開項目配置:在左樹視圖中雙擊項目名稱。從“目標”部分中選擇您的應用,然後選擇“信息”選項卡,然後展開“ URL類型”部分。
    2. 單擊+按鈕,然後為您的反向客戶端ID添加URL方案。要找到此值,請打開GoogleService-Info.plist配置文件,然後查找REVERSED_CLIENT_ID密鑰。複製該鍵的值,然後將其粘貼到配置頁上的“ URL方案”框中。將其他字段留空。

      完成後,您的配置應類似於以下內容(但具有特定於應用程序的值):

  2. 聲明應用程序委託實現了GIDSignInDelegate協議。

    迅速

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

    目標C

    AppDelegate.h
    @interface AppDelegate : UIResponder<UIApplicationDelegate, GIDSignInDelegate>
    
  3. 在您的應用程序委託的application:didFinishLaunchingWithOptions:方法中,配置FirebaseApp對象並設置登錄委託。

    迅速

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

    目標C

    // Use Firebase library to configure APIs
    [FIRApp configure];
    
    [GIDSignIn sharedInstance].clientID = [FIRApp defaultApp].options.clientID;
    [GIDSignIn sharedInstance].delegate = self;
    
  4. 實現您的應用程序委託的application:openURL:options:方法。該方法應調用GIDSignIn實例的handleURL方法,該方法將正確處理您的應用程序在身份驗證過程結束時收到的URL。

    迅速

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

    目標C

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

    為了使您的應用程序可以在iOS 8及更高版本上運行,還應實現已棄用的application:openURL:sourceApplication:annotation:方法。

    迅速

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

    目標C

    - (BOOL)application:(UIApplication *)application
                openURL:(NSURL *)url
      sourceApplication:(NSString *)sourceApplication
             annotation:(id)annotation {
      return [[GIDSignIn sharedInstance] handleURL:url];
    }
    
  5. 在應用程序委託中,通過定義以下方法,實現GIDSignInDelegate協議來處理登錄過程:

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

    迅速

    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. 在視圖控制器中,重寫viewDidLoad方法以設置GIDSignIn對象的顯示視圖控制器,並(可選)在可能的情況下以靜默方式登錄。

    目標C

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

    迅速

    GIDSignIn.sharedInstance()?.presentingViewController = self
    GIDSignIn.sharedInstance().signIn()
    
  7. GIDSignInButton添加到情節GIDSignInButton ,XIB文件或以編程方式實例化它。要將按鈕添加到情節GIDSignInButton或XIB文件中,請添加一個View並將其自定義類設置為GIDSignInButton
  8. 可選:如果要自定義按鈕,請執行以下操作:

    迅速

    1. 在視圖控制器中,將登錄按鈕聲明為屬性。
      @IBOutlet weak var signInButton: GIDSignInButton!
    2. 將按鈕連接到剛剛聲明的signInButton屬性。
    3. 通過設置GIDSignInButton對象的屬性來自定義按鈕。

    目標C

    1. 在視圖控制器的頭文件中,將登錄按鈕聲明為屬性。
      @property(weak, nonatomic) IBOutlet GIDSignInButton *signInButton;
    2. 將按鈕連接到剛剛聲明的signInButton屬性。
    3. 通過設置GIDSignInButton對象的屬性來自定義按鈕。

3.使用Firebase進行身份驗證

signIn:didSignInForUser:withError:方法中,從GIDAuthentication對象獲取Google ID令牌和Google訪問令牌,並將其交換為Firebase憑證:

迅速

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

目標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 {
    // ...
  }
}

最後,使用憑據對Firebase進行身份驗證:

迅速

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

物鏡

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

下一步

用戶首次登錄後,將創建一個新的用戶帳戶並將其鏈接到該用戶登錄的憑據(即用戶名和密碼,電話號碼或身份驗證提供者信息)。此新帳戶存儲為Firebase項目的一部分,可用於在項目中的每個應用程序中識別用戶,而無論用戶如何登錄。

  • 在您的應用程序中,您可以從FIRUser對象獲取用戶的基本配置文件信息。請參閱管理用戶

  • 在Firebase實時數據庫和雲存儲安全規則中,您可以從auth變量中獲取登錄用戶的唯一用戶ID,並使用它來控制用戶可以訪問哪些數據。

通過將身份驗證提供程序憑據鏈接到現有用戶帳戶,可以允許用戶使用多個身份驗證提供程序登錄您的應用程序

要註銷用戶,請致電signOut:

迅速

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

目標C

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

您可能還想為所有身份驗證錯誤添加錯誤處理代碼。請參閱處理錯誤