Как использовать 'verifyPhoneNumber ()' в Firebase, чтобы подтвердить владение телефоном # без использования # для входа? - PullRequest
3 голосов
/ 17 января 2020

Я использую react-native-firebase v5.6 в проекте.

Цель: В процессе регистрации пользователь вводит свой номер телефона, а затем отправляет OTP на указанный номер телефона. Я хочу иметь возможность сравнивать введенный пользователем код с кодом, отправленным из Firebase, чтобы иметь возможность предоставить доступ к следующим этапам регистрации.

Проблема: пользователь получает SMS OTP и все, но объект phoneAuthSnapshot, возвращаемый firebase.auth().verifyPhoneNumber(number).on('state_changed', (phoneAuthSnapshot => {}), не дает значения для кода, который отправил firebase, поэтому сравнивать пользователей не с чем введенный код с. Однако есть значение для свойства verificationId. Вот возвращаемый объект из вышеуказанного метода:

'Verification code sent', { 
  verificationId: 'AM5PThBmFvPRB6x_tySDSCBG-6tezCCm0Niwm2ohmtmYktNJALCkj11vpwyou3QGTg_lT4lkKme8UvMGhtDO5rfMM7U9SNq7duQ41T8TeJupuEkxWOelgUiKf_iGSjnodFv9Jee8gvHc50XeAJ3z7wj0_BRSg_gwlN6sumL1rXJQ6AdZwzvGetebXhZMb2gGVQ9J7_JZykCwREEPB-vC0lQcUVdSMBjtig',
  code: null,
  error: null,
  state: 'sent' 
}

Вот моя реализация на экране:

firebase
  .firestore()
  .collection('users')
  .where('phoneNumber', '==', this.state.phoneNumber)
  .get()
  .then((querySnapshot) => {
    if (querySnapshot.empty === true) {
      // change status
      this.setState({ status: 'Sending confirmation code...' });
      // send confirmation OTP
      firebase.auth().verifyPhoneNumber(this.state.phoneNumber).on(
        'state_changed',
        (phoneAuthSnapshot) => {
          switch (phoneAuthSnapshot.state) {
            case firebase.auth.PhoneAuthState.CODE_SENT:
              console.log('Verification code sent', phoneAuthSnapshot);
              this.setState({ status: 'Confirmation code sent.', confirmationCode: phoneAuthSnapshot.code });

              break;
            case firebase.auth.PhoneAuthState.ERROR:
              console.log('Verification error: ' + JSON.stringify(phoneAuthSnapshot));
              this.setState({ status: 'Error sending code.', processing: false });
              break;
          }
        },
        (error) => {
          console.log('Error verifying phone number: ' + error);
        }
      );
    }
  })
  .catch((error) => {
    // there was an error
    console.log('Error during firebase operation: ' + JSON.stringify(error));
  });

Как получить код, отправленный из Firebase, для возможности сравнения?

Ответы [ 3 ]

6 голосов
/ 19 января 2020

Поскольку @ christos-lytras имеет в свой ответ , код подтверждения не отображается в вашем приложении.

Это сделано из соображений безопасности, поскольку код, используемый для внеполосной аутентификации для самого устройства, позволит опытному пользователю просто извлечь код из памяти и выполнить аутентификацию, как если бы он имел доступ к этому номеру телефона.

Общий поток операций:

  1. Получите проверяемый номер телефона
  2. Используйте этот номер с verifyPhoneNumber() и кешируйте проверочный идентификатор, который он возвращает
  3. Запросите пользователь вводит код (или автоматически получает его)
  4. Объедините идентификатор и ввод пользователя вместе как учетные данные, используя firebase.auth.PhoneAuthProvider.credential(id, code)
  5. Попытка войти с этим учетные данные с использованием firebase.auth().signInWithCredential(credential)

В исходном коде вы также используете прослушиватель on(event, observer, errorCb, successCb) метода verifyPhoneNumber(phoneNumber). Однако этот метод также поддерживает прослушивание результатов с использованием Promises, что позволяет вам связывать цепочки с запросом Firebase. Это показано ниже.

Отправка кода подтверждения:

firebase
  .firestore()
  .collection('users')
  .where('phoneNumber', '==', this.state.phoneNumber)
  .get()
  .then((querySnapshot) => {
    if (!querySnapshot.empty) {
      // User found with this phone number.
      throw new Error('already-exists');
    }

    // change status
    this.setState({ status: 'Sending confirmation code...' });

    // send confirmation OTP
    return firebase.auth().verifyPhoneNumber(this.state.phoneNumber)
  })
  .then((phoneAuthSnapshot) => {
    // verification sent
    this.setState({
      status: 'Confirmation code sent.',
      verificationId: phoneAuthSnapshot.verificationId,
      showCodeInput: true // shows input field such as react-native-confirmation-code-field
    });
  })
  .catch((error) => {
    // there was an error
    let newStatus;
    if (error.message === 'already-exists') {
      newStatus = 'Sorry, this phone number is already in use.';
    } else {
      // Other internal error
      // see https://firebase.google.com/docs/reference/js/firebase.firestore.html#firestore-error-code
      // see https://firebase.google.com/docs/reference/js/firebase.auth.PhoneAuthProvider#verify-phone-number
      // probably 'unavailable' or 'deadline-exceeded' for loss of connection while querying users
      newStatus = 'Failed to send verification code.';
      console.log('Unexpected error during firebase operation: ' + JSON.stringify(error));
    }

    this.setState({
      status: newStatus,
      processing: false
    });
  });

Обработка кода подтверждения, полученного от пользователя:

codeInputSubmitted(code) {
  const { verificationId } = this.state;

  const credential = firebase.auth.PhoneAuthProvider.credential(
    verificationId,
    code
  );

  // To verify phone number without interfering with the existing user
  // who is signed in, we offload the verification to a worker app.
  let fbWorkerApp = firebase.apps.find(app => app.name === 'auth-worker')
                 || firebase.initializeApp(firebase.app().options, 'auth-worker');
  fbWorkerAuth = fbWorkerApp.auth();  
  fbWorkerAuth.setPersistence(firebase.auth.Auth.Persistence.NONE); // disables caching of account credentials

  fbWorkerAuth.signInWithCredential(credential)
    .then((userCredential) => {
      // userCredential.additionalUserInfo.isNewUser may be present
      // userCredential.credential can be used to link to an existing user account

      // successful
      this.setState({
        status: 'Phone number verified!',
        verificationId: null,
        showCodeInput: false,
        user: userCredential.user;
      });

      return fbWorkerAuth.signOut().catch(err => console.error('Ignored sign out error: ', err);
    })
    .catch((err) => {
      // failed
      let userErrorMessage;
      if (error.code === 'auth/invalid-verification-code') {
        userErrorMessage = 'Sorry, that code was incorrect.'
      } else if (error.code === 'auth/user-disabled') {
        userErrorMessage = 'Sorry, this phone number has been blocked.';
      } else {
        // other internal error
        // see https://firebase.google.com/docs/reference/js/firebase.auth.Auth.html#sign-inwith-credential
        userErrorMessage = 'Sorry, we couldn\'t verify that phone number at the moment. '
          + 'Please try again later. '
          + '\n\nIf the issue persists, please contact support.'
      }
      this.setState({
        codeInputErrorMessage: userErrorMessage
      });
    })
}

Ссылки на API:

Предлагаемый компонент ввода кода:

2 голосов
/ 19 января 2020

Firebase firebase.auth.PhoneAuthProvider не даст вам код для сравнения, вам придется использовать verificationId для проверки verificationCode, который вводит пользователь. В документации Firebase есть базовый c пример, в котором используется firebase.auth.PhoneAuthProvider.credential, а затем пытается войти с использованием этих учетных данных с помощью firebase.auth().signInWithCredential(phoneCredential):

firebase
  .firestore()
  .collection('users')
  .where('phoneNumber', '==', this.state.phoneNumber)
  .get()
  .then((querySnapshot) => {
    if (querySnapshot.empty === true) {
      // change status
      this.setState({ status: 'Sending confirmation code...' });
      // send confirmation OTP
      firebase.auth().verifyPhoneNumber(this.state.phoneNumber).on(
        'state_changed',
        (phoneAuthSnapshot) => {
          switch (phoneAuthSnapshot.state) {
            case firebase.auth.PhoneAuthState.CODE_SENT:
              console.log('Verification code sent', phoneAuthSnapshot);
              // this.setState({ status: 'Confirmation code sent.', confirmationCode: phoneAuthSnapshot.code });

              // Prompt the user the enter the verification code they get and save it to state
              const userVerificationCodeInput = this.state.userVerificationCode;
              const phoneCredentials = firebase.auth.PhoneAuthProvider.credential(
                phoneAuthSnapshot.verificationId, 
                userVerificationCodeInput
              );

              // Try to sign in with the phone credentials
              firebase.auth().signInWithCredential(phoneCredentials)
                .then(userCredentials => {
                  // Sign in successfull
                  // Use userCredentials.user and userCredentials.additionalUserInfo 
                })
                .catch(error => {
                  // Check error code to see the reason
                  // Expect something like:
                  // auth/invalid-verification-code
                  // auth/invalid-verification-id
                });

              break;
            case firebase.auth.PhoneAuthState.ERROR:
              console.log('Verification error: ' + JSON.stringify(phoneAuthSnapshot));
              this.setState({ status: 'Error sending code.', processing: false });
              break;
          }
        },
        (error) => {
          console.log('Error verifying phone number: ' + error);
        }
      );
    }
  })
  .catch((error) => {
    // there was an error
    console.log('Error during firebase operation: ' + JSON.stringify(error));
  });
0 голосов
/ 10 марта 2020

К сожалению, это не поддерживается firebase. Вход и выход после signInWithCredential может работать, но это очень запутанно

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...