通过 C++ 使用电话号码进行 Firebase 身份验证

使用 Firebase 身份验证,您可以通过向用户的电话发送短信来协助用户登录。用户可使用短信中包含的一次性代码进行登录。

本文介绍了如何使用 Firebase SDK 实现电话号码登录流程。

准备工作

  1. 将 Firebase 添加至您的 C++ 项目
  2. 如果您尚未将自己的应用与您的 Firebase 项目关联,请在 Firebase 控制台中进行关联。

对于 iOS 系统,请注意电话号码登录需要使用真机设备,在模拟器上无法实现。

安全问题

与其他可用的方法相比,仅使用电话号码进行身份验证的方式虽然便捷,但安全性较低,因为同一电话号码很容易流转给不同用户使用。此外,在具有多份用户个人资料的设备上,任何一位可以接收短信的用户都能使用该设备的电话号码登录帐号。

如果您在应用中使用电话号码登录机制,则应同时提供更安全的登录方法,并将使用电话号码登录的安全隐患告知用户。

为您的 Firebase 项目启用电话号码登录

要让用户能够通过短信登录,您必须先为 Firebase 项目启用电话号码登录功能,操作步骤如下:

  1. Firebase 控制台中,打开 Authentication(身份验证)部分。
  2. 登录方法页面上,启用电话号码登录方法。

Firebase 的电话号码登录请求的配额非常充足,大多数应用都不会遇到配额问题。但是,如果您需要通过电话号码身份验证让数量非常多的用户登录,则可能需要升级您的定价方案。请参阅定价页面。

开始接收 APNs 通知(仅限 iOS)

要在 iOS 上使用电话号码身份验证,您的应用必须能够接收来自 Firebase 的 APNs 通知。当您首次让用户通过电话号码在设备上登录时,Firebase 身份验证会向设备发送一条静默推送通知,以验证电话号码登录请求是否来自您的应用(因此,无法在模拟器上使用电话号码登录)。

启用 APNs 通知以用于 Firebase 身份验证:

  1. 在 Xcode 中为您的项目启用推送通知
  2. 将您的 APNs 证书上传到 Firebase。如果还没有 APNs 证书,请参阅配置 APNs SSL 证书

    1. 在 Firebase 控制台中,在您的项目内依次选择齿轮图标、项目设置以及云消息传递标签。

    2. 选择开发证书和/或生产证书对应的上传证书按钮。二者需要至少上传一个。

    3. 请为每种证书选择 .p12 文件,并提供密码(如有)。确保此证书的软件包 ID 与您应用的软件包 ID 匹配。选择保存

向用户的电话发送验证码

要启动电话号码登录流程,请向用户显示一个要求其提供电话号码的界面,然后调用 PhoneAuthProvider::VerifyPhoneNumber 以请求 Firebase 通过短信向用户电话发送身份验证码:

  1. 获取用户的电话号码。

    虽然相关的法律要求可能不尽相同,但为了避免用户不满,最佳做法是告知用户,如果他们选择使用电话登录,则可能会收到一条验证短信,并需按标准费率支付短信费用。

  2. 调用 PhoneAuthProvider::VerifyPhoneNumber,并向其传递用户的电话号码。
    class PhoneListener : public PhoneAuthProvider::Listener {
     public:
      ~PhoneListener() override {}
    
      void OnVerificationCompleted(Credential 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;
    PhoneAuthProvider& phone_provider = PhoneAuthProvider::GetInstance(auth);
    phone_provider->VerifyPhoneNumber(phone_number, kAutoVerifyTimeOut, null,
                                      &phone_listener);
    
    当您调用 PhoneAuthProvider::VerifyPhoneNumber 时:
    • 在 iOS 中,Firebase 会向您的应用发送一条静默推送通知。
    • Firebase 会向指定的电话号码发送一条包含验证码的短信,并将验证 ID 传递给您的完成函数。您将需要验证码和验证 ID 才能让用户登录。
  3. 保存验证 ID,并在应用加载时将其还原。这样可确保即使您的应用在用户完成登录流程之前被终止(例如,用户切换到短信应用时),您仍然拥有有效的验证 ID。

    您可以用任何方式留存验证 ID。如果您使用跨平台 C++ 框架编写代码,则应提供应用终止和还原的通知。发生这些事件时,您可以分别保存和还原验证 ID。

如果对 VerifyPhoneNumber 的调用导致在侦听器上调用 OnCodeSent,您可以在用户收到验证码短信时提示用户输入验证码。

另一方面,如果对 VerifyPhoneNumber 的调用导致 OnVerificationCompleted,则表示自动验证成功,您现在有了 Credential 并且可按下文所述的方式使用。

使用验证码让用户登录

用户将短信中的验证码提供给您的应用之后,根据验证码和验证 ID 创建一个 Credential 对象并将此对象传递给 Auth::SignInWithCredential

  1. 从用户处获取验证码。
  2. 根据验证码和验证 ID 创建 Credential 对象。
    Credential 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.
            const 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 != nullptr) {
      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();

发送以下问题的反馈:

此网页
需要帮助?请访问我们的支持页面