【问题标题】:How to verify that the email is authentic in Firebase?如何验证电子邮件在 Firebase 中的真实性?
【发布时间】:2022-08-22 00:30:32
【问题描述】:

我需要在我当前的代码中添加必要的功能和确切的代码,以便用户在登录之前必须验证电子邮件。

现在,用户注册并自动访问应用程序及其用户面板的所有功能。我想添加必要的功能,以便当用户注册时,会显示一条消息告诉他:您必须验证您的电子邮件这样我们确保它是有效的电子邮件并避免 SPA 用户的注册。

我需要用户验证她的电子邮件才能登录,在她这样做之前,她可以像以前一样继续使用该应用程序,而无需登录。

你可以看到我做了几个测试,其他用户试图帮助我,但我们没有达到必要的,因为我需要将功能添加到我现在拥有的代码中,因为这是我知道继续构建我的应用程序的唯一方法。

该应用程序已在Firebase 注册,通过电子邮件和密码注册,我使用Formik 控制表单的状态并使用Yup 进行验证。

我已阅读有关 \"Send a verification message to a user\" 的 Firebase 文档,

这是 Firebase 功能:

```
const auth = getAuth();
sendEmailVerification(auth.currentUser)
  .then(() => {
    // Email verification sent!
    // ...
  })
```

我现在使用的注册系统是邮件和密码。用户输入电子邮件、密码、验证密码并自动在应用程序中注册。

我做了几个测试,试图将 sendEmailVerification 添加到我的注册系统中,现在我所取得的是确认电子邮件到达用户(SPA 文件夹),但确认电子邮件在用户已经注册并使用该应用程序后到达。

用户必须在收到并确认“确认电子邮件”后才能注册

我需要一个适合我当前应用程序的代码示例,我不知道更改所有代码,这是我的应用程序的基础。

我该怎么做才能正常工作并且验证电子邮件在用户注册之前到达? 我在我的代码中做错了什么?

您可以测试使用Expo 构建的项目:

exp://exp.host/@miguelitolaparra/restaurantes-5-estrellas?release-channel=default

这是我用来注册用户的方法:

const formik = useFormik({
    initialValues: initialValues(),
    validationSchema: validationSchema(), // validate the form data
    validateOnChange: false,
    onSubmit: async(formValue) => {
      try { // send the data to Firebase
        const auth = getAuth()
       // sendEmailVerification(auth.currentUser)
        await createUserWithEmailAndPassword(
          auth,
          formValue.email,
          formValue.password
        )
      
       sendEmailVerification(auth.currentUser)

        navigation.navigate(screen.account.account)
      } catch (error) {
        // We use Toast to display errors to the user
        Toast.show({
          type: \"error\",
          position: \"bottom\",
          text1: \"Failed to register, please try again later\",
        })
      }
    },
  })

我还向您展示了完整的文件:

import { useFormik } from \'formik\'
import { getAuth, createUserWithEmailAndPassword, sendEmailVerification } from \'firebase/auth\'

export function RegisterForm() {
  const [showPassword, setShowPassword] = useState(false)
  const [showRepeatPassword, setShowRepeatPassword] = useState(false)

  const navigation = useNavigation()

  const formik = useFormik({
    initialValues: initialValues(),
    validationSchema: validationSchema(), // validate the form data
    validateOnChange: false,
    onSubmit: async (formValue) => {
      try { // send the data to Firebase
        const auth = getAuth()
        //sendEmailVerification(auth.currentUser)
        await createUserWithEmailAndPassword(
          auth,
          formValue.email,
          formValue.password
        )
      sendEmailVerification(auth.currentUser)

       
        navigation.navigate(screen.account.account)
      } catch (error) {
        // We use Toast to display errors to the user
        Toast.show({
          type: \"error\",
          position: \"bottom\",
          text1: \"Error al registrarse, intentelo mas tarde\",
        })
      }
    },
  })

  // function to hide or show the password
  const showHidenPassword = () => setShowPassword((prevState) => !prevState)
  const showHidenRepeatPassword = () => setShowRepeatPassword((prevState) => !prevState)

  return (
    // Registration form interface
    <View>
      <Input
        placeholder=\"Correo electronico\"
        keyboardType=\"email-address\"
        containerStyle={AuthStyles.input}
        rightIcon={
          <Icon type=\"material-community\" name=\"at\" iconStyle={AuthStyles.icon} />
        }
        onChangeText={(text) => formik.setFieldValue(\"email\", text)}
        errorMessage={formik.errors.email}
      />
      <Input
        placeholder=\"Contraseña\"
        containerStyle={AuthStyles.input}
        secureTextEntry={showPassword ? false : true}
        rightIcon={
          <Icon
            type=\"material-community\"
            name={showPassword ? \"eye-off-outline\" : \"eye-outline\"}
            iconStyle={AuthStyles.icon}
            onPress={showHidenPassword}
          />
        }
        onChangeText={(text) => formik.setFieldValue(\"password\", text)}
        errorMessage={formik.errors.password}
      />
      <Input
        placeholder=\"Repetir contraseña\"
        containerStyle={AuthStyles.input}
        secureTextEntry={showRepeatPassword ? false : true}
        rightIcon={
          <Icon
            type=\"material-community\"
            name={showRepeatPassword ? \"eye-off-outline\" : \"eye-outline\"}
            iconStyle={AuthStyles.icon}
            onPress={showHidenRepeatPassword}
          />
        }
        onChangeText={(text) => formik.setFieldValue(\"repeatPassword\", text)}
        errorMessage={formik.errors.repeatPassword}
      />
      <Button
        title=\"REGISTRATE\"
        containerStyle={AuthStyles.btnContainer}
        buttonStyle={AuthStyles.btn}
        onPress={formik.handleSubmit} // send the form
        loading={formik.isSubmitting}// show loading while doing user registration
      />
    </View>
  )
}

这是使用YupRegistreFormValidar.js 验证表单的文件

import * as Yup from \"yup\"

// object that has the elements of the form
export function initialValues() {
  return {
    email: \"\",
    password: \"\",
    repeatPassword: \"\",
  }
}

// validate the form data whit Yup
export function validationSchema() {
  return Yup.object({
    email: Yup.string()
      .email(\"El email no es correcto\")
      .required(\"El email es obligatorio\"),
    password: Yup.string().required(\"La contraseña es obligatoria\"),
  
    repeatPassword: Yup.string()  // validate that the passwords are the same
      .required(\"La contraseña es obligatoria\")
      .oneOf([Yup.ref(\"password\")], \"Las contraseñas tienen que ser iguales\"),
  })
}
  • 一些 sendmail 服务器支持VRFY,它可以让您在不发送电子邮件的情况下检查电子邮件地址的有效性,但这并不是通用的。还要确认您可以发送任何电子邮件
  • \"除了向用户发送验证消息之外,还有其他方法可以验证电子邮件是否正确吗?\" 你能澄清一下你的想法吗?我明白你的意思想做,但是怎么做那么您希望电子邮件验证机制能够正常工作吗?
  • “确认邮件没有到达他的电子邮件”这很可能意味着它被标记为垃圾邮件,无论是在他们的系统上还是在它到达之前。让用户检查他们的垃圾邮件文件夹,并查看stackoverflow.com/questions/72922475/…
  • 好的,只需尝试向自己发送任何电子邮件,以确保您在 Firebase 中启用了“电子邮件发送”
  • 为了向用户发送电子邮件,该用户必须登录到 Firebase 身份验证。是否允许已登录的任何人使用您的应用和访问数据,这取决于您并且取决于每个应用(许多应用不需要电子邮件验证,因此 Firebase 不能在 API 上要求这样做)等级)。如果您只想让他们这样做他们验证了他们的电子邮件地址,您可以在客户端代码、您拥有的任何服务器端代码以及数据库和存储的安全规则中检查他们的令牌/配置文件。

标签: javascript firebase react-native firebase-authentication


【解决方案1】:

您有多种选择来实现您的目的。 首先,要修复 SPA 问题,您可以使用自定义域,as shown on Firebase

要获得所需的内容,您可以按照以下步骤操作: 1 - 用户使用电子邮件地址注册。 2 - 新记录已创建,但状态为“待验证”并分配了激活字符串。 3 - 您发送用户数据和激活字符串,以及验证注册的链接。 4 - 用户单击链接,输入他们的数据,如果它们有效,则将状态更改为“活动”。

你可以尝试去做。 您还可以选择使用"Authenticate with Firebase via email link"

  • 要让用户通过电子邮件链接登录,您必须首先为您的 Firebase 项目启用电子邮件提供程序和电子邮件链接登录方法。

- 然后向用户的电子邮件地址发送一个身份验证链接。

要启动身份验证过程,请向用户显示一个界面,提示他们输入电子邮件地址,然后调用 sendSignInLinkToEmail 要求 Firebase 将身份验证链接发送到用户的电子邮件。

您可以在 Firebase 官方文档中查看所有详细信息 1 - 构建 ActionCodeSettings 对象,它为 Firebase 提供构建电子邮件链接的说明

const actionCodeSettings = {
  // URL you want to redirect back to. The domain (www.example.com) for this
  // URL must be in the authorized domains list in the Firebase Console.
  url: 'https://www.example.com/finishSignUp?cartId=1234',
  // This must be true.
  handleCodeInApp: true,
  iOS: {
    bundleId: 'com.example.ios'
  },
  android: {
    packageName: 'com.example.android',
    installApp: true,
    minimumVersion: '12'
  },
  dynamicLinkDomain: 'example.page.link'
};

2 - 向用户询问电子邮件。

3 - 将验证链接发送到用户的电子邮件并保存他们的电子邮件,以防用户在同一设备上使用电子邮件完成登录

import { getAuth, sendSignInLinkToEmail } from "firebase/auth";

const auth = getAuth();
sendSignInLinkToEmail(auth, email, actionCodeSettings)
  .then(() => {
    // The link was successfully sent. Inform the user.
    // Save the email locally so you don't need to ask the user for it again
    // if they open the link on the same device.
    window.localStorage.setItem('emailForSignIn', email);
    // ...
  })
  .catch((error) => {
    const errorCode = error.code;
    const errorMessage = error.message;
    // ...
  });

最后使用电子邮件链接完成访问。

这不是您正在寻找的,但它可能会有所帮助。

【讨论】:

  • 您的解决方案很有趣@MariaCruzFernandez,但我不能接受它,因为这不是我想要的。
【解决方案2】:

据我了解,您需要先验证用户的电子邮件地址,然后再创建用户。阻塞功能可能是您需要的。

exports.beforeCreate = functions.auth.user().beforeCreate((user, context) => {
  const locale = context.locale;
  if (user.email && !user.emailVerified) {
    // Send custom email verification on sign-up.
    return admin.auth().generateEmailVerificationLink(user.email).then((link) => {
      return sendCustomVerificationEmail(user.email, link, locale);
    });
  }
});

此 Firebase 函数将在新用户保存到 Firebase 身份验证数据库之前以及将令牌返回到您的客户端应用之前触发。但是,我认为在执行此功能后,会创建用户。为了防止创建用户,您可能必须实现更复杂的流程。

我能想到的一种天真的方法如下:向用户发送电子邮件后,不要终止函数,并在函数内部定期检查用户的电子邮件地址是否经过验证。还要设置一个超时选项并在超时后拒绝用户创建。正如预期的那样,这种方法会增加函数执行时间并且成本可能很高。

如果您对在 Firebase 身份验证数据库中创建的用户感到满意,我建议您实施文档中所述的解决方案。

exports.beforeCreate = functions.auth.user().beforeCreate((user, context) => {
  const locale = context.locale;
  if (user.email && !user.emailVerified) {
    // Send custom email verification on sign-up.
    return admin.auth().generateEmailVerificationLink(user.email).then((link) => {
      return sendCustomVerificationEmail(user.email, link, locale);
    });
  }
});

exports.beforeSignIn = functions.auth.user().beforeSignIn((user, context) => {
 if (user.email && !user.emailVerified) {
   throw new functions.auth.HttpsError(
     'invalid-argument', `"${user.email}" needs to be verified before access is granted.`);
  }
});

这将阻止未验证电子邮件的用户登录您的应用程序。

检查此文档以获取其他可能的选项:https://firebase.google.com/docs/auth/extend-with-blocking-functions#requiring_email_verification_on_registration

【讨论】:

  • 感谢您为准备答案所花费的麻烦@ayseasude,这确实非常好。问题是我不知道如何或在哪里可以将您的示例添加到我的代码中。你能给我更多关于我应该把它放在哪里的细节吗?谢谢,目前我不能接受你的回答,我也读过这个,但我不知道如何在我的文件中实现它而不破坏它太多
  • 这段代码与 Firebase Functions 一起部署,因此它不在客户端。如果您想使用这些功能,您的项目必须使用 Blaze 计划,并且您必须使用 Identity Platform 激活 Firebase 身份验证。将您的函数部署到云后,当用户登录时,它会自动运行(触发)。
  • 我认为这不是最适合我的,很抱歉,如您所见,提供奖励我说我需要一个详细而实用的答案。你告诉我的我已经读过了,任何人都可以添加一个像你给出的答案。对不起,我不能接受。感谢您的奉献@ayseasude 当然,到目前为止,我的应用程序不需要 Blaze 计划
猜你喜欢
  • 1970-01-01
  • 2017-04-19
  • 2021-11-21
  • 2017-06-12
  • 2017-05-30
  • 2020-07-16
  • 2021-07-10
  • 2021-10-10
相关资源
最近更新 更多