【问题标题】:How to do Phone Authentication in Flutter using Firebase?如何使用 Firebase 在 Flutter 中进行电话身份验证?
【发布时间】:2018-10-15 07:11:48
【问题描述】:

我搜索了很多网站,但没有找到使用 Firebase 在 Flutter 中实现电话身份验证的方法。谁能告诉我怎么做?

【问题讨论】:

标签: firebase flutter


【解决方案1】:

我遇到了同样的问题,但我正在构建一个 Ionic 应用程序。

您可以在网络上进行 Firebase 电话身份验证。 这个想法是:

  • 获取用户的电话号码并发送到网页。
  • 创建一个recaptchaVerifier

    var recaptchaVerifier = new firebase.auth.RecaptchaVerifier('recaptcha-container');
    
  • 使用电话号码登录用户:

    firebase.auth().signInWithPhoneNumber(phoneNumber, recaptchaVerifier)
            .then(confirmationResult => {
                myVerificationId = confirmationResult.verificationId;
            })
            .catch(error => {
                console.log('error', error);
            })
    
  • 通过深层链接将确认 ID 发送回 Flutter 应用

  • Firebase 将发送短信代码。

  • 使用任何采用确认 ID 和 代码作为参数。对于网络,它是这样的:

      let signinCredintial = firebase.auth.PhoneAuthProvider.credential(this.verificationId, this.code);
      firebase.auth().signInWithCredential(signinCredintial)
       .then(response => {
         // user is signed in
    
    })
    

【讨论】:

  • 我明白了。应该有一种方法来进行 Firebase 电话身份验证。如上所示,“signInWithPhoneNumber”方法不适用于 Firebase 对象。
【解决方案2】:

我已经在flutter中实现了带有firebase的电话auth singnIn,它非常简单,只需导入firebase_auth库并验证电话号码的格式是否正确,即它的开头有一个“+”号,后跟国家代码,然后是电话号码然后代码是这样的

if (phoneExp.hasMatch(phon))
   {
      final PhoneVerificationCompleted verificationCompleted=(FirebaseUser user){
        setState(() {
                      _message=Future<String>.value("auto sign in succedded $user");
                      debugPrint("Sign up succedded");
                      _pref.setString("phonkey",user.phoneNumber.toString());
                      MyNavigator.goToDetail(context);
//called when the otp is variefied automatically
                    });
      };
  final PhoneVerificationFailed verificationFailed=(AuthException authException){
    setState(() {
                  _message=Future<String>.value("verification failed code: ${authException.code}. Message: ${authException.message}");
                });
  };

  final PhoneCodeSent codeSent=(String verificationId,[int forceResendingToken]) async {
    this.verificationId=verificationId;


  };

  final PhoneCodeAutoRetrievalTimeout codeAutoRetrievalTimeout = (String verificationId){
    this.verificationId=verificationId;

  };

  await _auth.verifyPhoneNumber(
    phoneNumber: phon,
    timeout: Duration(seconds: 60),
    verificationCompleted: verificationCompleted,
    verificationFailed: verificationFailed,
    codeSent: codeSent,
    codeAutoRetrievalTimeout: codeAutoRetrievalTimeout
    );



}

如果手机无法检测到自动发送的 otp,则获取字符串中的 otp 并实现此功能

void _signInWithOtp() async{
  final FirebaseUser user = await _auth.signInWithPhoneNumber(
  verificationId: verificationId,
  smsCode: _otpController.text,
);

【讨论】:

    【解决方案3】:

    有据可查的工作演示项目here

    下面是详细过程

    步骤

    1. 询问用户的电话号码
    2. 从 Firebase 获取 OTP
    3. 登录 Firebase

    规则

    • 登录/登录方式相同。
    • OTP 仅用于获取AuthCrendential 对象
    • AuthCredential 对象是唯一用于登录用户的东西。 从verifyPhoneNumber中的verificationCompleted回调函数或PhoneAuthProvider获取。

    (不要担心,如果它令人困惑,继续阅读,你会明白的)

    工作流程

    1. 用户提供phoneNumber
    2. Firebase 发送 OTP
    3. 登录用户
      • 如果带有phoneNumber 的SIM 卡不在当前运行应用程序的设备中,
        • 我们必须先询问 OTP 并获取 AuthCredential 对象
        • 接下来我们可以使用AuthCredential来登录 即使phoneNumber 在设备中,此方法也有效
      • 否则,如果用户提供的 SIM 电话号码在运行应用程序的设备中,
        • 我们可以在没有 OTP 的情况下登录。
        • 因为来自submitPhoneNumber 函数的verificationCompleted 回调提供了登录用户所需的AuthCredential 对象
        • 但在前一种情况下,它没有被调用,因为 SIM 卡不在手机中。

    功能

    • 提交电话号码
    Future<void> _submitPhoneNumber() async {
        /// NOTE: Either append your phone number country code or add in the code itself
        /// Since I'm in India we use "+91 " as prefix `phoneNumber`
        String phoneNumber = "+91 " + _phoneNumberController.text.toString().trim();
        print(phoneNumber);
    
        /// The below functions are the callbacks, separated so as to make code more readable
        void verificationCompleted(AuthCredential phoneAuthCredential) {
          print('verificationCompleted');
          ...
          this._phoneAuthCredential = phoneAuthCredential;
          print(phoneAuthCredential);
        }
    
        void verificationFailed(AuthException error) {
          ...
          print(error);
        }
    
        void codeSent(String verificationId, [int code]) {
          ...
          print('codeSent');
        }
    
        void codeAutoRetrievalTimeout(String verificationId) {
          ...
          print('codeAutoRetrievalTimeout');
        }
    
        await FirebaseAuth.instance.verifyPhoneNumber(
          /// Make sure to prefix with your country code
          phoneNumber: phoneNumber,
    
          /// `seconds` didn't work. The underlying implementation code only reads in `milliseconds`
          timeout: Duration(milliseconds: 10000),
    
          /// If the SIM (with phoneNumber) is in the current device this function is called.
          /// This function gives `AuthCredential`. Moreover `login` function can be called from this callback
          verificationCompleted: verificationCompleted,
    
          /// Called when the verification is failed
          verificationFailed: verificationFailed,
    
          /// This is called after the OTP is sent. Gives a `verificationId` and `code`
          codeSent: codeSent,
    
          /// After automatic code retrival `tmeout` this function is called
          codeAutoRetrievalTimeout: codeAutoRetrievalTimeout,
        ); // All the callbacks are above
      }
    
    • 提交OTP
    void _submitOTP() {
        /// get the `smsCode` from the user
        String smsCode = _otpController.text.toString().trim();
    
        /// when used different phoneNumber other than the current (running) device
        /// we need to use OTP to get `phoneAuthCredential` which is inturn used to signIn/login
        this._phoneAuthCredential = PhoneAuthProvider.getCredential(
            verificationId: this._verificationId, smsCode: smsCode);
    
        _login();
      }
    
    • 登录/登录
    Future<void> _login() async {
        /// This method is used to login the user
        /// `AuthCredential`(`_phoneAuthCredential`) is needed for the signIn method
        /// After the signIn method from `AuthResult` we can get `FirebaserUser`(`_firebaseUser`)
        try {
          await FirebaseAuth.instance
              .signInWithCredential(this._phoneAuthCredential)
              .then((AuthResult authRes) {
            _firebaseUser = authRes.user;
            print(_firebaseUser.toString());
          });
          ...
        } catch (e) {
          ...
          print(e.toString());
        }
      }
    
    • 退出
      Future<void> _logout() async {
        /// Method to Logout the `FirebaseUser` (`_firebaseUser`)
        try {
          // signout code
          await FirebaseAuth.instance.signOut();
          _firebaseUser = null;
          ...
        } catch (e) {
          ...
          print(e.toString());
        }
      }
    

    更多实现细节请参考lib/main.dart文件here

    如果您发现问题,欢迎对此答案和repo README进行编辑

    【讨论】:

    • 我试过了,这个应用程序在 android 中崩溃并且没有在 iOS 中安装。我按照从 firebase 生成的 google.json 文件获取了整个代码更新包。
    • @codeFreak 我没有 MacBook,所以你需要在 iOS 端进行配置。此外,我再次检查了该应用程序正在运行。请尝试在 Firebase 端进行配置,或确保您在测试设备上启用了互联网连接。我不知道你哪里出了问题。尝试所有可能性。
    • @Mohith7548 我正在尝试在一个颤振应用程序中实现这一点,该应用程序使用谷歌电子邮件地址进行注册。那么,由于身份验证过程是基于电子邮件地址处理的,我是否可以使用电话身份验证?我只需要在应用中实现OTP验证。
    • @Bhawna Firebase 提供不同的身份验证提供程序,您可以在身份验证部分打开它们。您可以使用电子邮件或电话号码登录用户。但同时两者是不可能的。
    【解决方案4】:

    目前_signInPhoneNumber 已被弃用,所以使用这个:

    try {
        AuthCredentialauthCredential = PhoneAuthProvider.getCredential(verificationId: verificationId, verificationsCode: smsCode);
    
        await _firebaseAuth
          .signInWithCredential(authCredential)
          .then((FirebaseUser user) async {
             final FirebaseUser currentUser = await _firebaseAuth.currentUser();
             assert(user.uid == currentUser.uid);
             print('signed in with phone number successful: user -> $user');
        }
    }
    

    【讨论】:

      【解决方案5】:

      使用flutter_otp 包轻松发送带有一次性密码的短信。优点是:

      1. 您可以发送自定义 OTP 消息。
      2. OTP 可以在任何范围内生成。

      使用示例:

       import 'package:flutter_otp/flutter_otp.dart';
      
       ...
      
       FlutterOtp myOtpObj = FlutterOtp();
       myOtpObj.sendOtp('7975235555');
      
       ...
      
       // you can check as follows
       bool correctOrNot = myOtpObj.resultChecker(<OTP entered by user>);
      

      查看 flutter_otp 存储库here

      【讨论】:

      • 谁为这个包裹中的短信付费?
      【解决方案6】:

      以下是步骤:-

      1. 根据电话号码获取一次性密码:-

        void sendOTP(String phoneNumber, PhoneCodeSent codeSent,
              PhoneVerificationFailed verificationFailed) {
            if (!phoneNumber.contains('+')) phoneNumber = '+91' + phoneNumber;
            _firebaseAuth.verifyPhoneNumber(
                phoneNumber: phoneNumber,
                timeout: Duration(seconds: 30),
                verificationCompleted: null,
                verificationFailed: verificationFailed,
                codeSent: codeSent,
                codeAutoRetrievalTimeout: null);   }
        
      2. 使用 codeSent 函数获取验证 ID 并将其传递给 OTP 屏幕

        void codeSent(String verificationId, [int forceResendingToken]) {
        Navigator.push(
            context,
            MaterialPageRoute(
                builder: (context) => Otp(
                      phoneNumber: _phoneNumber,
                      verificationId: verificationId,
                    )));
        }
        
      3. 根据verification_id和OTP获取用户

        Future<bool> verifyOTP(String verificationId, String otp) async {
        AuthCredential credential = PhoneAuthProvider.getCredential(
          verificationId: verificationId,
          smsCode: otp,
        );
        AuthResult result;
        try {
          result = await _firebaseAuth.signInWithCredential(credential);
        } catch (e) {
          // throw e;
          return false;
        }
        print(result);
        (await result.user.getIdToken()).claims.forEach((k, v) {
          print('k= $k and v= $v');
        });
        if (result.user.uid != null) return true;
        return false;
        }
        

      更多详情请关注下方video

      https://youtu.be/e5M3EwJJYS4

      【讨论】:

        猜你喜欢
        • 2020-02-21
        • 2021-06-10
        • 1970-01-01
        • 2021-02-12
        • 2018-07-03
        • 2019-03-05
        • 2019-08-05
        • 2020-01-23
        • 2021-05-03
        相关资源
        最近更新 更多