iOS/Swift:如何用Firebase验证用户邮箱但不用于认证?
解决方案:自定义邮箱验证流程(不影响手机号登录)
完全可以实现需求,不需要修改Firebase Auth的用户登录方式,全程基于Firestore和云函数自定义验证流程,步骤如下:
1. 完善Firestore用户数据结构
确保你的users集合下的用户文档包含以下字段:
phoneNumber: 已认证的手机号(来自Firebase Auth)marketingEmail: 用户添加的营销邮箱emailVerified: 布尔值,初始为false
2. 编写云函数触发验证邮件发送
创建一个Firestore触发器云函数,当用户文档的marketingEmail字段被新增或更新时,自动生成验证令牌并发送邮件:
const functions = require("firebase-functions"); const admin = require("firebase-admin"); const jwt = require("jsonwebtoken"); // 需要提前安装jsonwebtoken包 admin.initializeApp(); // 生成带过期时间的验证令牌 function generateVerificationToken(userId, email) { return jwt.sign( { userId, email }, functions.config().jwt.secret, // 在Firebase控制台配置JWT密钥 { expiresIn: "7d" } // 设置令牌7天内有效 ); } // 发送验证邮件 async function sendVerificationEmail(email, token) { const verificationUrl = `https://your-project-id.cloudfunctions.net/verifyEmail?token=${token}`; const mailOptions = { from: "你的应用 <noreply@your-app.com>", to: email, subject: "验证你的营销邮箱", html: `<p>点击以下链接完成邮箱验证:</p><a href="${verificationUrl}">验证邮箱</a>` }; // 这里假设使用Firebase官方的「Trigger Email」扩展,写入mail集合即可触发发送 await admin.firestore().collection("mail").add(mailOptions); } // Firestore触发器:监测营销邮箱字段变更 exports.onMarketingEmailUpdated = functions.firestore .document("users/{userId}") .onUpdate(async (change, context) => { const beforeData = change.before.data(); const afterData = change.after.data(); // 仅当营销邮箱新增或变更时执行逻辑 if (beforeData?.marketingEmail !== afterData?.marketingEmail && afterData.marketingEmail) { const token = generateVerificationToken(context.params.userId, afterData.marketingEmail); await sendVerificationEmail(afterData.marketingEmail, token); } return null; });
3. 编写验证邮箱的HTTP云函数
创建一个HTTP云函数,处理用户点击验证链接后的请求,更新Firestore的emailVerified状态:
exports.verifyEmail = functions.https.onRequest(async (req, res) => { const token = req.query.token; if (!token) { return res.status(400).send("缺少验证令牌"); } try { const decoded = jwt.verify(token, functions.config().jwt.secret); const userId = decoded.userId; const email = decoded.email; // 校验用户文档中的邮箱是否与令牌一致 const userDoc = await admin.firestore().collection("users").doc(userId).get(); if (!userDoc.exists || userDoc.data().marketingEmail !== email) { return res.status(400).send("无效的验证请求"); } // 更新邮箱验证状态 await userDoc.ref.update({ emailVerified: true }); res.send("邮箱验证成功!"); // 也可以改为跳转至App Deeplink,引导用户返回应用 } catch (error) { res.status(400).send("验证令牌无效或已过期"); } });
关键注意事项
- 全程无需修改Firebase Auth的用户记录,用户登录方式始终保持手机号认证,与营销邮箱验证流程完全独立。
- JWT密钥需要在本地执行
firebase functions:config:set jwt.secret="你的自定义密钥"完成配置,再部署云函数。 - 邮件发送也可集成SendGrid、Mailgun等第三方服务,替代Firebase的「Trigger Email」扩展,实现更灵活的邮件定制。
内容的提问来源于stack exchange,提问作者John
相关产品推荐
相关产品推荐

