React Native 短信验证码已过期,请重新发送验证码重试

0g0grzrc  于 2023-11-21  发布在  React
关注(0)|答案(3)|浏览(389)

每当我尝试使用react-native-firebase sdk用电话号码登录时,我都会通过短信收到OTP代码,当我提交收到的代码时,会出现一个错误:“短信代码已过期。请重新发送验证码再试一次。”这里需要注意的是,即使有错误,相应电话号码的条目也会写入firebase的用户部分。
我正在使用以下:

NodeJS: v8.11.1,
NPM: v5.6.0,
react-native: "^0.59.9",
react-native-firebase: "^5.5.3"

字符串
我已经尝试过的一些链接是:

1. https://github.com/invertase/react-native-firebase- 
docs/blob/master/docs/auth/phone-auth.md
2. https://stackoverflow.com/questions/46522726/firebase-phone- 
authentication-error-the-sms-code-has-expired
3. https://www.bountysource.com/issues/45308170-firebase-phone- 
number-auth-integration
4. https://medium.com/@chrisbianca/getting-started-with-firebase- 
authentication-on-react-native-a1ed3d2d6d91
5. https://invertase.io/oss/react-native-firebase/v6/auth/phone- 
auth


在MobileRegistration.js中:

navigateToOtpScreen() {
console.log("Phone number: ", "+91" + this.state.phoneNumber)
firebase.auth().signInWithPhoneNumber("+91" + 
this.state.phoneNumber)
.then(confirmResult => {
   this.setState({ confirmResult, message: 'Code has been sent!'})
   this.props.navigation.navigate('EnterOtp', { 'confirmResult': 
   confirmResult})
 })
 .catch(error => {
      alert(error.message);
      this.setState({ message: `Sign In With Phone Number Error: 
      ${error.message}` })
  });


};
在EnterOtp.js中:

componentDidMount() {
this.unsubscribe = firebase.auth().onAuthStateChanged((user) => {
    alert(JSON.stringify(user));
    if (user) {
        this.setState({
            user: user.toJSON()
        });
    } else {
        // User has been signed out, reset the state
        this.setState({
            user: null,
            message: '',
            otp: '',
            otp1: '',
            otp2: '',
            otp3: '',
            otp4: '',
            otp5: '',
            otp6: ''

        });
    }
});


}

componentWillUnmount() {
if (this.unsubscribe) this.unsubscribe();


}

verifyOTP = async () => {
const {
    confirmResult,
} = this.props.navigation.state.params;
let otp = this.state.otp + "" + this.state.otp1 + "" + this.state.otp2 + "" + this.state.otp3 + "" + this.state.otp4 + "" + this.state.otp5 + "" + this.state.otp6
if (confirmResult && otp.length) {

    alert(otp);
    confirmResult.confirm(otp).then((user) => {
            AsyncStorage.setItem('accessToken', confirmResult._verificationId);
            this.props.navigation.navigate('SetupCoverVideo');
            this.setState({
                message: 'Code Confirmed!'
            });
        })
        .catch(error => {
            alert(error.message) && this.setState({
                message: `Code Confirm Error: ${error.message}`
            })
        });
}


}
预期结果:应验证代码,并且应在firebase的用户部分中输入条目,并导航至SetupCoverVideo。
实际结果:面对一个错误说:“短信代码已过期。请重新发送验证码再试一次。”这里要注意的是,即使有错误,相应电话号码的条目也会写入Firebase的用户部分。
我想知道解决办法,请帮助我。

4ngedf3f

4ngedf3f1#

显然,最近的一些Android版本已经足够智能,可以接收短信验证码并使用它来认证用户。这种认证在后台进行,而**用户仍然在短信中接收验证码。当用户尝试输入验证码时,他/她会收到一条消息,表明验证码已过期,因为Android已经使用了它(在后台),并且已经登录了用户!要仔细检查,请检查Firebase控制台。您应该会发现此新用户已添加到用户列表中。
为了避免收到验证码过期消息,我们需要设置一个
身份验证更改
监听器
。当Android后台登录用户时,这个监听器应该引导用户离开登录界面,用户应该在登录界面输入验证码。下面演示了如何实现这一点。我将在登录界面添加以下代码。
用于功能组件的示例代码:

useEffect( () => {
    firebase.auth().onAuthStateChanged( (user) => {
        if (user) {
            // Obviously, you can add more statements here, 
            //       e.g. call an action creator if you use Redux. 

            // navigate the user away from the login screens: 
            props.navigation.navigate("PermissionsScreen");
        } 
        else 
        {
            // reset state if you need to  
            dispatch({ type: "reset_user" });
        }
    });
}, []);

字符串
用于类组件的示例代码:

// I did NOT test this version, because I use functional components. 
componentDidMount() {
    firebase.auth().onAuthStateChanged( (user) => {
        if (user) {
            // Obviously, you can add more statements here, 
            //       e.g. call an action creator if you use Redux. 

            // navigate the user away from the login screens: 
            props.navigation.navigate("PermissionsScreen");
        } 
        else 
        {
            // reset state if you need to 
            this.setState({
                user: null,
                messageText: '',
                codeInput: '',
                phoneNo: '',
                confirmResult: null,
            });
        }
    });
};

bnlyeluc

bnlyeluc2#

您需要使用以下方法检查后台身份验证:

conponentDidMount() {    
firebase.auth().onAuthStateChanged((user) => {
            if (user) {
                // alert(JSON.stringify(user))
                // Obviously, you can add more statements here, 
                //       e.g. call an action creator if you use Redux. 
                // navigate the user away from the login screens: 
            }
        });
}

字符串
然后,您需要注销您的用户,一旦你完成了它(我面临着这个问题的旧用户会话已经存在,而新用户来验证)
因此,在注销时用途:

if (firebase.auth().currentUser)
            firebase.auth().currentUser.delete();


一切都准备好了!

vc9ivgsu

vc9ivgsu3#

我发现问题是上述(Android试图在后台自动处理).我发现的解决方案是将一个监听内的方法,验证phoneSignin.见下文:

Future<void> createUserWithPhone(
  {required String phoneNumber,
  required BuildContext context,
  required Function(bool esteEumNovoUser) verifyCompleted,
  required Function(String erroMsg) failed,
  required Function(String generatedCodeId) codeSent,
  required VoidCallback codeRetrieveTimeout}) async {
FirebaseAuth auth = FirebaseAuth.instance;

//create a listener that will handle the signing
var listener = FirebaseAuth.instance.authStateChanges();
//place the listener to handle the login and the automatic login in 
 background
listener.listen((User? user) {
  if (user != null) {
    debugPrint('logged in');
    final DateTime? dataCriacao = user.metadata.creationTime;
    final DateTime dataAgora = DateTime.now();

    if (dataCriacao != null) {
      debugPrint(dataCriacao.toString());
      final Duration difference = dataAgora.difference(dataCriacao);
      final int minutesDifference = difference.inMinutes;
      //if difference is short, we know its a new user
      if (minutesDifference <= 3) {
       
         newUserCreated(); //now you proceed with your code, probably 
          //creating a new entry in Firestore
         //verifyCompleted(true) in My code I use this callback
        listener.listen((event) {}).cancel();

      } else {
        
        existingUserLoggin();//was a existing user, handle the result
        //verifyCompleted(false) in My code I use this callback
        listener.listen((event) {}).cancel();
   
      }
    } else {
      debugPrint('novo user');
      newUserCreated(); //if no datacreation available, its a new user
      //verifyCompleted(true) in My code I use this callback
      listener.listen((event) {}).cancel();

    }
  } else {
    debugPrint('not logged in, do nothing');
  }
});

//keep the phoneLogin logic of firebase to create the user in backend for 
//you
await auth.verifyPhoneNumber(
  timeout: const Duration(seconds: 60),
  phoneNumber: '+55$phoneNumber',
  verificationCompleted: (PhoneAuthCredential credential) {
    debugPrint(credential.toString());
    debugPrint('Verificação completa');

    //Disconsider this block of code bellow, you are now handling it
    //on listener above.
    // ANDROID ONLY!
    // Sign the user in (or link) with the auto-generated credential
    /*
    signInWithPhone(
        credential: credential,
        createUser: () {
          verifyCompleted(true);
        },
        signinThisUser: () {
          verifyCompleted(false);
        });*/
  },
  verificationFailed: (FirebaseAuthException e) {
    debugPrint('failed');
    debugPrint(e.message);
    debugPrint(e.code);
    debugPrint(e.toString());
    if (e.code == 'invalid-phone-number') {
      failed('Você informou um número inválido');
    } else {
      failed('Ocorreu um erro. Tente novamente em instantes');
    }
  },
  codeSent: (String verificationId, int? resendToken) {
    debugPrint('code sent');
    debugPrint(verificationId);

    codeSent(verificationId);
  },
  codeAutoRetrievalTimeout: (String verificationId) {
    debugPrint('acabou o tempo de timedout');
    MySnack().displaySnackBar(context, 'entrou em 
    codeAutoRetrievalTimeout');
    codeRetrieveTimeout();
    },
   );
 }

字符串

相关问题