전화번호와 C++를 사용하여 Firebase 인증

Firebase 인증을 사용하면 사용자의 전화로 SMS 메시지를 전송하여 로그인하는 것이 가능합니다. 사용자는 SMS 메시지에 포함된 일회용 코드를 사용하여 로그인합니다.

이 문서에서는 Firebase SDK를 사용하여 전화번호 로그인 과정을 구현하는 방법을 설명합니다.

시작하기 전에

  1. C++ 프로젝트에 Firebase를 추가합니다.
  2. 아직 Firebase 프로젝트에 앱을 연결하지 않았다면 Firebase Console에서 연결합니다.
  3. 전화번호 로그인의 플랫폼 요구사항을 알아보세요.
    • 전화번호 로그인은 모바일 플랫폼에만 사용할 수 있습니다.
    • iOS의 경우 전화번호 로그인에 실제 기기가 필요하며 시뮬레이터에서는 작동하지 않습니다.

보안 문제

전화번호만 사용하는 인증은 편리하기는 하지만, 전화번호 소유권은 사용자 간에 쉽게 이전될 수 있으므로 다른 방식보다 보안성이 떨어집니다. 또한 기기에 여러 사용자 프로필이 있는 경우 SMS 메시지를 받을 수 있는 사람이라면 누구든지 기기의 전화번호로 계정에 로그인할 수 있습니다.

앱에서 전화번호 기반 로그인을 사용하는 경우 더 안전한 로그인 방법을 함께 제공해야 하고, 전화번호 로그인을 사용하면 보안이 약화된다는 점을 사용자에게 알려야 합니다.

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

SMS 메시지로 사용자를 로그인 처리하려면 우선 Firebase 프로젝트에서 전화번호 로그인 방법을 사용 설정해야 합니다.

  1. Firebase Console에서 인증 섹션을 엽니다.
  2. 로그인 방법 페이지에서 전화번호 로그인 방법을 사용 설정합니다.

Firebase의 전화번호 로그인 요청 할당량은 대부분의 앱에서 불편을 겪지 않을 정도로 충분히 높습니다. 그러나 전화번호 인증으로 처리할 로그인 사용자가 매우 많다면 요금제를 업그레이드해야 할 수도 있습니다. 자세한 내용은 가격 책정 페이지를 참조하세요.

APN 알림 수신 시작(Apple 플랫폼)

Apple 플랫폼에서 전화번호 인증을 사용하려면 앱이 Firebase의 APN 알림을 수신할 수 있어야 합니다. 기기에서 처음으로 전화번호를 통해 사용자를 로그인시키면 Firebase 인증에서 기기로 자동 푸시 알림을 전송하여 앱에서 전화번호 로그인 요청을 보냈는지 확인합니다. 따라서 시뮬레이터에서는 전화번호 로그인을 사용할 수 없습니다.

Firebase 인증과 함께 사용하기 위해 APN 알림을 사용 설정하는 방법은 다음과 같습니다.

  1. Xcode에서 프로젝트에 푸시 알림을 사용 설정합니다.
  2. Firebase에 APN 인증서를 업로드합니다. 아직 APN 인증서가 없다면 Apple Developer Member Center에서 만드세요.

    1. Firebase Console의 프로젝트 내에서 톱니바퀴 아이콘을 선택하고 프로젝트 설정을 선택한 다음 클라우드 메시징 탭을 선택합니다.

    2. 개발 인증서, 프로덕션 인증서 또는 모든 인증서에 대해 인증서 업로드 버튼을 선택합니다. 하나 이상은 반드시 필요합니다.

    3. 각 인증서에 대해 .p12 파일을 선택하고 해당되는 경우 비밀번호를 입력합니다. 이 인증서의 번들 ID가 앱의 번들 ID와 일치해야 합니다. 저장을 선택합니다.

사용자 전화로 인증 코드 전송

전화번호 로그인을 시작하려면 사용자에게 전화번호를 제공하도록 요청하는 인터페이스를 표시하고 PhoneAuthProvider::VerifyPhoneNumber를 호출하여 Firebase에서 사용자의 휴대전화에 SMS 메시지로 인증 코드를 전송하도록 요청합니다.

  1. 사용자의 전화번호를 확인합니다.

    지역에 따라 현지 법규가 다르지만, 일반적으로는 사용자가 제반 상황을 미리 알 수 있도록 전화 로그인을 사용하면 인증용 SMS 메시지가 발송되고 일반 요금이 부과될 수 있다는 점을 알려야 합니다.

  2. PhoneAuthProvider::VerifyPhoneNumber를 호출하면서 사용자의 전화번호를 전달합니다.
    class PhoneListener : public PhoneAuthProvider::Listener {
     public:
      ~PhoneListener() override {}
    
      void OnVerificationCompleted(PhoneAuthCredential credential) override {
        // Auto-sms-retrieval or instant validation has succeeded (Android only).
        // No need for the user to input the verification code manually.
        // `credential` can be used instead of calling GetCredential().
      }
    
      void OnVerificationFailed(const std::string& error) override {
        // Verification code not sent.
      }
    
      void OnCodeSent(const std::string& verification_id,
                      const PhoneAuthProvider::ForceResendingToken&
                          force_resending_token) override {
        // Verification code successfully sent via SMS.
        // Show the Screen to enter the Code.
        // Developer may want to save that verification_id along with other app states in case
        // the app is terminated before the user gets the SMS verification code.
      }
    };
    
    PhoneListener phone_listener;
    PhoneAuhtOptions options;
    options.timeout_milliseconds = kAutoVerifyTimeOut;
    options.phone_number = phone_number;
    PhoneAuthProvider& phone_provider = PhoneAuthProvider::GetInstance(auth);
    phone_provider->VerifyPhoneNumber(options, &phone_listener);
    
    PhoneAuthProvider::VerifyPhoneNumber를 호출하면 Firebase가 다음을 수행합니다.
    • iOS의 경우 앱에 사용자 모르게 푸시 알림을 보냅니다.
    • 지정된 전화번호로 인증 코드가 포함된 SMS 메시지를 보내고 완료 함수에 인증 ID를 전달합니다. 인증 코드와 인증 ID가 모두 있어야 사용자를 로그인 처리할 수 있습니다.
  3. 인증 ID를 저장한 후 앱이 로드되면 이를 복원합니다. 이렇게 하면 사용자가 로그인 과정을 완료하기 전에 앱이 종료되더라도(예: SMS 앱으로 전환) 올바른 인증 ID를 유지할 수 있습니다.

    인증 ID를 유지하는 방법에는 제한이 없습니다. 교차 플랫폼 C++ 프레임워크를 작성하는 경우 앱 종료 및 복원에 대한 알림을 제공해야 합니다. 이러한 이벤트에서 인증 ID를 각각 저장하고 복원할 수 있습니다.

VerifyPhoneNumber 호출로 인해 리스너에서 OnCodeSent가 호출되면 사용자에게 SMS 메시지로 받은 인증 코드를 입력하라는 메시지를 표시할 수 있습니다.

반면 VerifyPhoneNumber에 대한 호출이 OnVerificationCompleted를 반환하면 자동 인증에 성공한 것이며 이제 아래의 설명과 같이 사용할 수 있는 PhoneAuthCredential을 갖게 됩니다.

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

사용자가 SMS 메시지의 인증 코드를 앱에 제공하면 인증 코드와 인증 ID를 사용하여 PhoneAuthCredential 객체를 만들고 이 객체를 Auth::SignInWithCredential에 전달합니다.

  1. 사용자로부터 인증 코드를 받습니다.
  2. 인증 코드와 인증 ID를 사용하여 Credential 객체를 만듭니다.
    PhoneAuthCredential credential = phone_auth_provider->GetCredential(
        verification_id_.c_str(), verification_code.c_str());
        
  3. Credential 객체로 사용자를 로그인시킵니다.
    Future<User> future = auth_->SignInWithCredential(credential);
    future.OnCompletion(
        [](const Future<User*>& result, void*) {
          if (result.error() == kAuthErrorNone) {
            // Successful.
            // User is signed in.
            User user = *result.result();
    
            // This should display the phone number.
            printf("Phone number: %s", user.phone_number().c_str());
    
            // The phone number provider UID is the phone number itself.
            printf("Phone provider uid: %s", user.uid().c_str());
    
            // The phone number providerID is 'phone'
            printf("Phone provider ID: %s", user.provider_id().c_str());
          } else {
            // Error.
            printf("Sign in error: %s", result.error_message().c_str());
          }
        },
        nullptr);
    

다음 단계

사용자가 처음으로 로그인하면 신규 사용자 계정이 생성되고 사용자가 로그인할 때 사용한 사용자 인증 정보(사용자 이름과 비밀번호, 전화번호 또는 인증 제공업체 정보)에 연결됩니다. 이 신규 계정은 Firebase 프로젝트에 저장되며 사용자의 로그인 방법과 무관하게 프로젝트 내의 모든 앱에서 사용자를 식별하는 데 사용할 수 있습니다.

  • 앱의 firebase::auth::User 객체에서 사용자의 기본 프로필 정보를 가져올 수 있습니다.

    firebase::auth::User user = auth->current_user();
    if (user.is_valid()) {
      std::string name = user.display_name();
      std::string email = user.email();
      std::string photo_url = user.photo_url();
      // The user's ID, unique to the Firebase project.
      // Do NOT use this value to authenticate with your backend server,
      // if you have one. Use firebase::auth::User::Token() instead.
      std::string uid = user.uid();
    }
    
  • Firebase 실시간 데이터베이스와 Cloud Storage 보안 규칙auth 변수에서 로그인한 사용자의 고유 사용자 ID를 가져온 후 이 ID를 통해 사용자가 액세스할 수 있는 데이터를 관리할 수 있습니다.

인증 제공업체의 사용자 인증 정보를 기존 사용자 계정에 연결하면 사용자가 여러 인증 제공업체를 통해 앱에 로그인할 수 있습니다.

사용자를 로그아웃시키려면 SignOut()을 호출합니다.

auth->SignOut();