[iOS] - FireBase를 통한 SMS전화번호 인증하기

Firebase로 전화번호 인증

🚨 GoogleService-Info.plist를 추가하기 전에 원격저장소(Github)에 프로젝트를 업로드한다면 제거하고 올리는 것을 권장 (개인정보 유출 가능성이 있습니다.)

iOS에서 전화번호로 Firebase에 인증

Firebase 프로젝트에서 전화번호 로그인 사용 설정

  • Console에서 Authetication섹션에서 Sign in method탭에서 전화를 제공합니다.

앱 인증 사용 설정

전화번호 인증을 사용하려면 Firebase에서 전화번호 로그인 요청이 내 앱에서 발생한 것인지 확인할 수 있어야 합니다.

  1. Silent APN 알림 : 기기에서 처음으로 전화번호를 통해 사용자를 로그인 처리하면 Firebase 인증에서 사용자 모르게 기기로 푸시 알림을 전송하여 토큰을 보냅니다.
    • iOS 8.0이상은 silent notification은 사용자의 권한요청이 필수가 아닙니다.
  2. reCAPTCHA 인증 : 사용자가 앱의 백그라운드 새로고침을 중지했거나 iOS 시뮬레이터에서 앱을 테스트하는 경우와 같이 자동 푸시 알림을 주고받을 수 없는 경우, Firebase 인증은 reCAPTCHA 인증을 사용하여 전화번호 로그인 과정을 완료합니다.

사용자 전화로 인증 코드 보내기

사용자에게 전화번호를 제공하도록 요청하는 UI를 작성한 후, verifyPhoneNumber:UIDelegate:completion: 를 호출하여 Firebase가 사용자의 전화에 SMS로 인증 코드를 전송하도록 요청합니다.

var phoneNumber = "123-456-789" // 전화번호 

PhoneAuthProvider.provider()
  .verifyPhoneNumber(phoneNumber, uiDelegate: nil) { verificationID, error in
      if let error = error {
        self.showMessagePrompt(error.localizedDescription)
        return
      }
      // 에러가 없다면 사용자에게 인증코드와 verificationID(인증ID) 전달
  }
  • verifyPhoneNumber:UIDelegate:completion: 가 호출하면 Firebase가 앱에 사용자 모르게 푸시 알림을 보내거나 사용자에게 reCAPTCHA 챌린지를 표시합니다.
  • 지정된 전화번호로 인증코드가 포함된 SMS메시지를 보낸 후 성공적으로 처리되면 인증ID를 전달합니다.
    • 전달된 인증 ID는 UserDefault 및 DB에 저장합니다.
  • Auth 인스턴스의 languageCode 속성을 사용하여 인증언어를 지정하면 SMS메시지를 현지화할 수 있습니다.
    Auth.auth().languageCode = "kr"

권장사항

  1. 지역마다 법에따라 다르지만, 일반적으로 사용자에게 SMS메시지가 발송되고 요금이 발생할 수 있다는 점을 알려야 합니다.

인증코드로 사용자 로그인 처리

정상적으로 인증코드와 인증ID를 받았다면 signInWithCredential:completion: 를 호출하여 FIRPhoneAuthCredential 객체를 만든 후 사용자로그인합니다.

  • FIRPhoneAuthCredential 객체 생성
    let credential = PhoneAuthProvider.provider().credential(
      withVerificationID: verificationID,
      verificationCode: verificationCode
    )
  • FIRPhoneAuthCredential 객체를 사용하여 로그인
    Auth.auth().signIn(with: credential) { authResult, error in
        if let error = error {
          print(error.debugDescription)
        }
        // 인증 완료 -> 로그인 진행
    }

가상 전화번호로 할당량제한 없이 테스트하기

가상전화번호로 테스트 장점

  1. 할당량을 소모하지 않고 전화번호 인증을 테스트합니다.
  2. 실제 SMS 메시지를 보내지 않고 전화번호 인증을 테스트합니다.
  3. 동일한 전화번호로 연속으로 테스트를 하는경우 위험없이 실행할 수 있습니다. (앱스토어 리뷰과정에서 리뷰어가 같은 전화번호로 테스트를 할 때 reject의 위험을 최소화할 수 있습니다.)
  4. 시뮬레이터에서 테스트를 쉽게 할 수 있습니다.
  5. 실제 전화번호에 적용되는 보안검사를 하지않고 테스트를 할 수 있습니다.

가상전화번호를 위한 요구사항

  1. 실제로 존재하지 않는 전화번호를 사용해야합니다.
  2. 가상전화번호는 최대 10개까지 추가할 수 있습니다.
  3. 추측하기 어려운 테스트 전화번호/코드를 사용하고 자주 변경합니다.
  4. 전화번호는 길이 및 기타 제약 조건에 따라 올바른 형식이어야 합니다.(실제번호처럼 동일한 유효성검사를 진행합니다.)

가상전화번호 생성하기

  • Console에서 Authetication섹션에서 Sign in method탭에서 전화번호를 제공합니다.

  • 로그인이 완료되면 해당전화번호로 Firebase사용자가 생성됩니다.

  • 사용자는 실제 전화번호 사용자와 동일한 행동 및 속성을 가지며 동일한 방식으로 실시간 데이터베이스/Cloud Firestore 및 기타 서비스에 액세스할 수 있습니다. 이 과정에서 생성된 ID 토큰은 실제 전화번호 사용자와 동일한 서명을 갖습니다.

  • Control Access with Custom Claims and Security Rules - Firebase Admin SDK는 사용자계정 커스텀을 지원합니다.

    • 사용자에게 데이터나 리소스에 접근할 관리자권한을 줄 수 있습니다.
    • 사용자가 속한 다른 그룹을 정의할 수 있습니다.
    • 다양한 단계 접근을 제공합니다.
      • 유료/무료 가입자
      • 관리자 및 일반사용자
      • 교사 및 학생

통합 테스트

Swizzling 없이 전화번호 로그인

Swizzling이란? 런타임때 어떤 메서드를 다른 메서드로 바꾸는 것을 말합니다.

Firebase가 silent push notification으로 APNs 토큰을 얻거나, reCAPTCHA 지정한 custom scheme으로 리다이렉트를 하는 과정에서 Swizzling을 합니다.

  • swizzling 사용하지 않는다면 명시적으로 APNs 토큰을 전달하고 redirect URL도 제공해야합니다.

Swizzling 비활성화

  • info.plist에서 FirebaseAppDelegateProxyEnabled 속성울 추가한 후 No로 설정합니다. (Firebase 모든 products에서 swizzling 비활성화) ****
  1. APNs device token 얻기

    func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
      // 디바이스토큰을 auth에 전달
      Auth.auth().setAPNSToken(deviceToken, type: .prod)
    
      // 앱에서 필요한 경우 디바이스토큰 추가 처리
      // ...
    }
  2. redirect URL

    // AppDelegate.swift
    
    // iOS 9이상
    func application(_ application: UIApplication, open url: URL,
        options: [UIApplicationOpenURLOptionsKey : Any]) -> Bool {
      if Auth.auth().canHandle(url) {
        return true
      }
    }
    
    // iOS 9미만
    func application(_ application: UIApplication,
                     open url: URL,
                     sourceApplication: String?,
                     annotation: Any) -> Bool {
      if Auth.auth().canHandle(url) {
        return true
      }
    }
    
    // SceneDelegate.swift
    func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
      for urlContext in URLContexts {
          let url = urlContext.url
          Auth.auth().canHandle(url)
      }
    }

사용자가 로그인 되면 Firebase프로젝트에 정보가 저장

  • 사용자가 처음 로그인하면 새로운 사용자 계정이 생성되고 사용자 이름 및 암호, 전화 번호 또는 인증 공급자 정보와 같은 자격 증명에 연결됩니다.
  • 새로운 계정은 Firebase 프로젝트의 일부로 저장되며, 사용자가 로그인하는 방법에 관계없이 프로젝트의 모든 앱에서 사용자를 식별하는 데 사용할 수 있습니다.
  • Firebase 실시간 데이터베이스 및 클라우드 저장소 보안 규칙에서는 auth 변수에서 로그인한 사용자의 고유 사용자 ID를 가져와 사용자가 액세스할 수 있는 데이터를 제어할 수 있습니다.
  • Link Multiple Auth Providers to an Account on Apple Platforms
  • 인증 세부적인 에러처리 - Handle Firebase Apple Platforms Auth Errors

로그아웃

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

💡 Authentication vs Authorization vs Certification

  1. Authentication
    • (사용 또는 입장하는 상황에서) 인증
    • ex. 로그인하는 절차
  2. Authorization
    • (권한) 인증
    • ex. 로그인 한 계정이 관리자인지, 일반사용자인지 구분하는 절차
  3. Certification
    • (심사를 통과한) 인증
    • 일정 기준을 넘었을때 주어지는 것

참고링크

좋은 웹페이지 즐겨찾기