iOS/SwiftUI

SwiftUI - Apple Sign In With Firebase

🥭Mango 2023. 3. 14. 21:19

안녕하세요 :D 망고입니다🥭

SwiftUI로 Firebase와 연동한 Apple 로그인 하는 방법에 대해 알아보겠습니다.

Firebase

Firebase 홈페이지에서 새 프로젝트를 생성하고 Authentication로 간 뒤

Sign-in-method에서 새 제공업체 추가를 누르고 Apple을 추가해준다.

 


그 다음 Xcode로 돌아와 SPM을 이용해 firebase SDK(github.com/firebase/firebase-ios-sdk.git) 를 설치한다.

PROJECT -> Package Dependencies ->  + 버튼 클릭

firebase-ios-sdk를 설치해주고

FirebaseAuth를 선택해 Add Packge해준다.

Apple

Apple 로그인을 사용하기 위해서 https://developer.apple.com/account/resources/identifiers/list 로 이동한 뒤

Identifiers에서 +버튼을 눌러 추가해준다.


 

App IDs를 클릭하고 Continue 해준다.


Description과 Bundle ID를 넣어준다.


Capabilities에서 Sign In with Apple을 선택하고 저장해준다.

 

Xcode로 돌아가 TARGETS -> Signing&Capabilities 에서 + 버튼을 눌러 Sign in with Apple을 추가해준다.

 

 

Code

import AuthenticationServices
SignInWithAppleButton { (request) in
                        loginData.nonce = randomNonceString()
                        request.requestedScopes = [.email, .fullName]
                        request.nonce = sha256(loginData.nonce)
                        
                    } onCompletion: { (result) in
                        switch result {
                        case .success(let user):
                            print("success")
                            guard let credential = user.credential as? ASAuthorizationAppleIDCredential else {
                                print("error with firebase")
                                return
                            }
                            loginData.authenticate(credential: credential)
                        case .failure(let error):
                            print(error.localizedDescription)
                        }
                    }

원하는 위치에 SignInWithAppleButton 만들어준다.


import Firebase
import CryptoKit
import AuthenticationServices
class LoginViewModel: ObservableObject {
    
    @Published var nonce = ""
    
    func authenticate(credential: ASAuthorizationAppleIDCredential) {
        //getting token
        guard let token = credential.identityToken else {
            print("error with firebase")
            return
        }
        
        guard let tokenString = String(data: token, encoding: .utf8) else {
            print("error with token")
            return
        }
        
        let firebaseCredential = OAuthProvider.credential(withProviderID: "apple.com", idToken: tokenString, rawNonce: nonce)
        Auth.auth().signIn(with: firebaseCredential) { result, err in
            if let err = err {
                print(err.localizedDescription)
            }
            
            print("로그인 완료")
        }
    }
}

// Helper for Apple Login with Firebase
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
}

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
}

import SwiftUI
//import Firebase

@main
struct 앱 이름: App {
    
    //@UIApplicationDelegateAdaptor(AppDelegate.self) var delegate 
    
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

/*
class AppDelegate: NSObject, UIApplicationDelegate {
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
        FirebaseApp.configure()
        return true
    }
}
*/

주석 처리 된 부분을 추가해준다.

 

Firebase로 가면 로그인이 된걸 확인할 수 있다.