Google 로그인을 앱에 통합하여 사용자가 Google 계정으로 Firebase에 인증하도록 설정할 수 있습니다.
시작하기 전에
- iOS 프로젝트에 Firebase를 추가합니다.
Podfile
에 다음 pod를 추가합니다.pod 'Firebase/Auth' pod 'GoogleSignIn'
- 아직 Firebase 프로젝트에 앱을 연결하지 않았다면 Firebase Console에서 연결합니다.
- Firebase Console에서 Google 로그인을 사용 설정합니다.
- Firebase Console에서 인증 섹션을 엽니다.
- 로그인 방법 탭에서 Google 로그인 방법을 사용 설정하고 저장을 클릭합니다.
1. 필수 헤더 파일 가져오기
먼저 Firebase SDK과 Google 로그인 SDK의 헤더 파일을 앱으로 가져와야 합니다.
Swift
앱 대리자에서 다음의 헤더 파일을 가져옵니다.
import Firebase import GoogleSignIn
로그인 뷰의 뷰 컨트롤러에서 다음의 헤더 파일을 가져옵니다.
import Firebase import GoogleSignIn
Objective-C
앱 대리자에서 다음의 헤더 파일을 가져옵니다.
@import Firebase; @import GoogleSignIn;
로그인 뷰의 뷰 컨트롤러에서 다음의 헤더 파일을 가져옵니다.
@import Firebase; @import GoogleSignIn;
2. Google 로그인 구현
다음 단계를 진행하여 Google 로그인을 구현합니다. iOS에서 Google 로그인을 사용하는 방법은 Google 로그인 개발자 문서에서 자세히 볼 수 있습니다.
- 다음과 같이 Xcode 프로젝트에 맞춤 URL 스키마를 추가합니다.
- 왼쪽 트리 보기에서 프로젝트 이름을 두 번 클릭하여 프로젝트 구성을 엽니다. 대상 섹션에서 앱을 선택하고 정보 탭을 선택한 후 URL 유형 섹션을 펼칩니다.
- + 버튼을 클릭하고 반전된 클라이언트 ID의 URL 스키마를 추가합니다. 이 값을 찾으려면
구성 파일을 열고GoogleService-Info.plist REVERSED_CLIENT_ID
키를 찾습니다. 이 키의 값을 복사하여 구성 페이지의 URL 스키마 상자에 붙여넣습니다. 다른 필드는 비워 둡니다.완성된 구성은 다음과 같은 형태이며 애플리케이션별 값이 적용됩니다.
- 앱 대리자가
GIDSignInDelegate
프로토콜을 구현한다고 선언합니다.Swift
AppDelegate.swift
:class AppDelegate: UIResponder, UIApplicationDelegate, GIDSignInDelegate {
Objective-C
AppDelegate.h
:@interface AppDelegate : UIResponder<UIApplicationDelegate, GIDSignInDelegate>
- 앱 대리자의
application:didFinishLaunchingWithOptions:
메서드에서FirebaseApp
객체를 구성하고 로그인 대리자를 설정합니다.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;
- 앱 대리자의
application:openURL:options:
메서드를 구현합니다. 이 메서드는GIDSignIn
인스턴스의handleURL
메서드를 호출하여 인증 프로세스가 끝날 때 애플리케이션이 수신하는 URL을 적절히 처리합니다.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]; }
앱을 iOS 8 이상에서 실행하려면 지원이 중단된
application:openURL:sourceApplication:annotation:
메서드도 구현합니다.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]; }
- 앱 대리자에서
GIDSignInDelegate
프로토콜을 구현하고 다음의 메서드를 정의하여 로그인 프로세스를 처리합니다.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. // ... }
- 뷰 컨트롤러에서
viewDidLoad
메서드를 재정의하여GIDSignIn
객체의 프레젠테이션 뷰 컨트롤러를 설정하고, 가능한 경우 자동으로 로그인합니다(선택사항).Objective-C
[GIDSignIn sharedInstance].presentingViewController = self; [[GIDSignIn sharedInstance] signIn];
Swift
GIDSignIn.sharedInstance()?.presentingViewController = self GIDSignIn.sharedInstance().signIn()
- 스토리보드나 XIB 파일에
GIDSignInButton
을 추가하거나 프로그래매틱 방식으로 인스턴스화합니다. 스토리보드 또는 XIB 파일에 버튼을 추가하려면 뷰를 추가하고 커스텀 클래스를GIDSignInButton
으로 설정합니다. - 선택: 버튼을 맞춤설정하려면 다음 절차를
진행합니다.
Swift
- 뷰 컨트롤러에서 로그인 버튼을 속성으로 선언합니다.
@IBOutlet weak var signInButton: GIDSignInButton!
- 버튼을 방금 선언한
signInButton
속성에 연결합니다. - GIDSignInButton 객체의 속성을 설정하여 버튼을 맞춤설정합니다.
Objective-C
- 뷰 컨트롤러의 헤더 파일에서 로그인 버튼을 속성으로 선언합니다.
@property(weak, nonatomic) IBOutlet GIDSignInButton *signInButton;
- 버튼을 방금 선언한
signInButton
속성에 연결합니다. - GIDSignInButton 객체의 속성을 설정하여 버튼을 맞춤설정합니다.
- 뷰 컨트롤러에서 로그인 버튼을 속성으로 선언합니다.
3. Firebase에 인증
signIn:didSignInForUser:withError:
메서드에서 GIDAuthentication
객체로부터 Google ID 토큰과 Google 액세스 토큰을 가져와서 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 { // ... } }
마지막으로 Firebase 사용자 인증 정보를 사용해 Firebase에 인증합니다.
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; // ... }];
다음 단계
사용자가 처음으로 로그인하면 신규 사용자 계정이 생성되고 사용자 인증 정보(사용자가 로그인할 때 사용한 사용자 이름과 비밀번호, 전화번호 또는 인증 제공업체 정보)에 연결됩니다. 이 신규 계정은 Firebase 프로젝트에 저장되며 사용자의 로그인 방법과 무관하게 프로젝트 내의 모든 앱에서 사용자 본인 확인에 사용할 수 있습니다.
Firebase 실시간 데이터베이스와 Cloud Storage 보안 규칙의
auth
변수에서 로그인한 사용자의 고유 사용자 ID를 가져온 후 이 ID를 통해 사용자가 액세스할 수 있는 데이터를 관리할 수 있습니다.
인증 제공업체의 사용자 인증 정보를 기존 사용자 계정에 연결하면 사용자가 여러 인증 제공업체를 통해 앱에 로그인할 수 있습니다.
사용자를 로그아웃시키려면 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; }
또한 모든 인증 오류에 대한 오류 처리 코드를 추가할 수도 있습니다. 오류 처리를 참조하세요.