React与Firebase开发:如何将邮箱验证链接改为邮箱OTP验证?
将邮箱验证链接改为OTP的修改方案
Firebase自带的sendEmailVerification方法仅支持发送验证链接,无法直接生成并发送邮箱OTP。要实现你需要的功能,有两种可行方案,以下是具体修改步骤:
方案一:基于Firebase无密码登录(推荐新手使用)
这种方案利用Firebase的无密码邮箱登录功能,通过自定义邮件模板,将登录链接中的验证码作为OTP展示给用户,用户输入该验证码即可完成邮箱验证。
步骤1:配置Firebase控制台
- 进入Firebase控制台 → 你的项目 → Authentication → 登录方法
- 启用「邮箱/密码」和「邮箱链接(无密码登录)」选项
- 进入模板 → 选择「密码登录(链接)」模板,修改邮件内容,提取链接中的
oobCode参数作为OTP(比如将链接替换为你的邮箱验证码是:{{actionCode}})
步骤2:修改前端代码
import { getAuth, createUserWithEmailAndPassword, sendSignInLinkToEmail, isSignInWithEmailLink, signInWithEmailLink } from "firebase/auth"; const auth = getAuth(); const actionCodeSettings = { url: `${window.location.origin}/verify-email`, // 你的验证页面地址 handleCodeInApp: true, }; // 注册函数 const signup = () => { createUserWithEmailAndPassword(auth, user.email, user.password) .then((userCredential) => { // 发送包含OTP的登录链接邮件 return sendSignInLinkToEmail(auth, user.email, actionCodeSettings); }) .then(() => { // 保存邮箱到本地存储,用于后续验证 window.localStorage.setItem('emailForSignIn', user.email); alert("包含验证码的邮件已发送"); }) .catch((error) => { alert(error.message); }); }; // 验证页面的OTP验证函数(比如在/verify-email页面) const verifyEmailWithOTP = (otp) => { const email = window.localStorage.getItem('emailForSignIn'); // 构造包含OTP的登录链接 const signInLink = `${window.location.origin}/verify-email?oobCode=${otp}`; if (isSignInWithEmailLink(auth, signInLink)) { signInWithEmailLink(auth, email, signInLink) .then((userCredential) => { // 登录成功后,邮箱自动标记为已验证 window.localStorage.removeItem('emailForSignIn'); alert("邮箱验证成功"); }) .catch((error) => { alert("验证码错误或已过期"); }); } };
方案二:自定义OTP生成与验证(需要云函数)
这种方案需要自己生成OTP、存储验证信息,并通过Firebase云函数发送邮件,适合需要完全自定义OTP逻辑的场景。
步骤1:创建Firebase云函数发送邮件
首先安装nodemailer依赖:
npm install nodemailer
然后编写云函数(functions/index.js):
const functions = require("firebase-functions"); const nodemailer = require("nodemailer"); const admin = require("firebase-admin"); admin.initializeApp(); // 配置邮件发送器(使用Gmail或其他SMTP服务) const transporter = nodemailer.createTransport({ service: "Gmail", auth: { user: "your-email@gmail.com", pass: "your-app-password", }, }); // 生成6位OTP const generateOTP = () => { return Math.floor(100000 + Math.random() * 900000).toString(); }; // 云函数:发送邮箱OTP exports.sendEmailOTP = functions.https.onCall(async (data, context) => { const { email, uid } = data; const otp = generateOTP(); const expirationTime = Date.now() + 15 * 60 * 1000; // 15分钟过期 // 将OTP和过期时间存储到Firestore await admin.firestore().collection("emailOTPs").doc(uid).set({ otp, expirationTime, email, }); // 发送邮件 const mailOptions = { from: "Your App <your-email@gmail.com>", to: email, subject: "你的邮箱验证码", text: `你的验证码是:${otp},15分钟内有效。`, }; await transporter.sendMail(mailOptions); return { success: true }; });
步骤2:修改前端代码
import { getAuth, createUserWithEmailAndPassword } from "firebase/auth"; import { getFunctions, httpsCallable } from "firebase/functions"; import { getFirestore } from "firebase/firestore"; const auth = getAuth(); const functions = getFunctions(); const db = getFirestore(); const sendEmailOTP = httpsCallable(functions, "sendEmailOTP"); // 注册函数 const signup = () => { createUserWithEmailAndPassword(auth, user.email, user.password) .then((userCredential) => { const uid = userCredential.user.uid; // 调用云函数发送OTP return sendEmailOTP({ email: user.email, uid }); }) .then(() => { alert("验证码已发送至你的邮箱"); }) .catch((error) => { alert(error.message); }); }; // OTP验证函数 const verifyOTP = (otp) => { const user = auth.currentUser; if (!user) return; // 查询Firestore中的OTP信息 db.collection("emailOTPs").doc(user.uid).get() .then((doc) => { if (!doc.exists) throw new Error("验证码不存在"); const { otp: storedOTP, expirationTime } = doc.data(); if (Date.now() > expirationTime) throw new Error("验证码已过期"); if (otp !== storedOTP) throw new Error("验证码错误"); // 验证成功,标记邮箱为已验证 return user.updateEmailVerified(true); }) .then(() => { // 删除已使用的OTP return db.collection("emailOTPs").doc(user.uid).delete(); }) .then(() => { alert("邮箱验证成功"); }) .catch((error) => { alert(error.message); }); };
内容的提问来源于stack exchange,提问作者Divya Agarwal
相关产品推荐
相关产品推荐

