[UIKit] Firebase Chat App: Apple Sign In & Sign Out

Junyoung Park·2022년 9월 17일
0

UIKit

목록 보기
35/142
post-thumbnail

Apple을 사용하여 인증

Firebase Chat App: Apple Sign In & Sign Out

구현 목표

구현 태스크

  1. 애플 로그인 사전 등록
  2. 애플 로그인 버튼 UI 및 로그인 함수
  3. 유저 데이터 → 파이어베이스 실시간 데이터베이스 등록 및 확인

핵심 코드

    private let appleLoginButton: ASAuthorizationAppleIDButton = {
        let button = ASAuthorizationAppleIDButton(type: .signIn, style: .whiteOutline)
        return button
    }()
  • 애플 로그인 버튼 UI
    @objc private func appleSignIn() {
        startSignInWithAppleFlow()
    }
  • 로그인 버튼 클릭 시 실행 함수
    func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) {
        guard
            let appleIDCredential = authorization.credential as? ASAuthorizationAppleIDCredential,
            let nonce = currentNonce,
            let appleIDToken = appleIDCredential.identityToken,
            let idTokenString = String(data: appleIDToken, encoding: .utf8) else {
            return
        }
        
        let userIdentifier = appleIDCredential.user
        let firstName = appleIDCredential.fullName?.givenName ?? ""
        let lastName = appleIDCredential.fullName?.familyName ?? ""
        let email = appleIDCredential.email ?? ""
        
        DatabaseManager.shared.userExists(with: userIdentifier, at: .Apple) { exists in
            if !exists {
                DatabaseManager.shared.insertUser(with: ChatAppUser(firstName: firstName, lastName: lastName, emailAddress: email, platform: .Apple, userIdentifier: userIdentifier))
            }
        }
        
        let credential = OAuthProvider.credential(withProviderID: "apple.com", idToken: idTokenString, rawNonce: nonce)
        // credential sign in
        FirebaseAuth.Auth.auth().signIn(with: credential) { [weak self] result, error in
            guard let self = self else { return }
            guard
                let result = result,
                error == nil else {
                if let error = error {
                    print(error.localizedDescription)
                }
                return
            }
            print("Successfully Apple Sign In")
            NotificationCenter.default.post(name: .didSignInNotification, object: nil)
        }
    }
  • 애플 로그인 정보 → 최초 로그인 경우만 이메일 및 유저 정보 리턴 가능
  • 모든 경우 동일한 user 값을 파이어베이스 데이터베이스 키 값으로 확인
  • 로그인 성공 시 노티피케이션 포스팅
extension SignInViewController: ASAuthorizationControllerDelegate, ASAuthorizationControllerPresentationContextProviding {
    func presentationAnchor(for controller: ASAuthorizationController) -> ASPresentationAnchor {
        return self.view.window!
    }
    
    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
    }
    
    @available(iOS 13, *)
    private 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()
    }
    
    @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
    }
}
  • 애플 아이디 사용을 위한 난수 값 생성 함수 및 관련 델리게이트 함수 등록

구현 화면

profile
JUST DO IT

0개의 댓글