使用 Firebase Authentication,您可以向用户的手机发送短信以协助其登录,用户使用短信中包含的一次性验证码即可登录。
本文介绍了如何使用 Firebase SDK 实现电话号码登录流程。
准备工作
- 将 Firebase 添加到您的 C++ 项目。
- 如果您尚未将您的应用与 Firebase 项目关联,请在 Firebase 控制台中进行关联。
- 了解电话号码登录的平台要求:
- 电话号码登录仅适用于移动平台。
- iOS 系统需要实体设备才能实现电话号码登录,在模拟器上无法实现此功能。
安全考量
与其他可用的方法相比,仅使用电话号码进行身份验证的方法虽然便捷,但安全性较低,因为电话号码的所有权可以很容易地在用户之间转移。此外,在具有多份用户个人资料的设备上,任何一位可以接收短信的用户都能使用该设备的电话号码登录账号。
如果您选择在应用中使用电话号码登录方法,应同时提供更安全的登录方法,并将使用电话号码登录的安全隐患告知用户。
为 Firebase 项目启用电话号码登录方法
如需让用户能够通过短信登录,您必须先为 Firebase 项目启用电话号码登录方法,步骤如下:
- 在 Firebase 控制台中,打开 Authentication 部分。
- 在登录方法页面上,启用电话号码登录方法。
开始接收 APNs 通知(Apple 平台)
如需在 Apple 平台上使用电话号码身份验证,您的应用必须能够接收来自 Firebase 的 APNs 通知。当用户首次通过电话号码在设备上登录时,Firebase Authentication 会向设备发送一条静默推送通知,以验证电话号码登录请求是否来自您的应用(此原因导致无法在模拟器上使用电话号码进行登录)。
如需启用 APNs 通知以用于 Firebase Authentication,请执行以下操作:
- 在 Xcode 中为您的项目启用推送通知。
将您的 APNs 证书上传到 Firebase。如果您还没有 APNs 证书,请务必在 Apple Developer Member Center 内创建一个。
-
在 Firebase 控制台中,在您的项目内依次选择齿轮图标 > 项目设置 > Cloud Messaging 标签页。
-
选择开发证书和/或生产证书对应的上传证书按钮。二者至少需要选择其一。
-
为每个证书选择 .p12 文件,并提供密码(如有)。确保此证书的软件包 ID 与您应用的软件包 ID 匹配。选择保存。
-
向用户的电话发送验证码
如需启动电话号码登录,请向用户显示一个提示其输入电话号码的界面,然后调用 PhoneAuthProvider::VerifyPhoneNumber
以请求 Firebase 通过短信向用户电话发送身份验证码:
-
获取用户的电话号码。
虽然相关的法律要求可能不尽相同,但为了避免用户不满,最佳做法是告知用户,如果他们选择使用电话号码登录方式,则可能会收到一条验证短信,并需按标准费率支付短信费用。
- 调用
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 中)向您的应用发送一条静默推送通知,
- 向指定的电话号码发送一条包含验证码的短信,并将验证 ID 传递给您的完成函数。您需要有验证码和验证 ID 才能让用户登录。
-
保存验证 ID,并在应用加载时将其还原。这样可确保即使您的应用在用户完成登录流程之前被终止(例如,用户切换到短信应用时),您仍然保留有效的验证 ID。
您可以用任何方式保存验证 ID。如果您使用跨平台 C++ 框架编写代码,该框架应该会提供应用终止和还原的通知。在这些情况下,您可以分别保存和还原验证 ID。
如果对 VerifyPhoneNumber
的调用导致在监听器上调用 OnCodeSent
,您可以在用户收到验证码短信时提示用户输入验证码。
另一方面,如果对 VerifyPhoneNumber
的调用导致 OnVerificationCompleted
,则表示自动验证成功,您现在有了 PhoneAuthCredential
并且可按下文所述的方式使用。
使用验证码让用户登录
用户将短信中的验证码提供给您的应用之后,系统会根据验证码和验证 ID 创建一个 PhoneAuthCredential
对象并将此对象传递给 Auth::SignInWithCredential
,以便让用户登录。
- 从用户处获取验证码。
- 根据验证码和验证 ID 创建
Credential
对象。PhoneAuthCredential credential = phone_auth_provider->GetCredential( verification_id_.c_str(), verification_code.c_str());
- 使用
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 Realtime Database 和 Cloud Storage 安全规则中,您可以从
auth
变量获取已登录用户的唯一用户 ID,然后利用此 ID 来控制用户可以访问哪些数据。
您可以通过将身份验证提供方凭据关联至现有用户账号,让用户可以使用多个身份验证提供方登录您的应用。
如需将用户退出登录,请调用 SignOut()
:
auth->SignOut();