如何在Firebase Cloud Functions中生成撤销邮箱变更的操作链接
自定义Firebase邮箱变更撤销功能实现方案
Firebase官方Admin SDK目前没有直接生成邮箱变更撤销链接的原生接口,你需要自行实现完整的撤销逻辑,具体步骤如下:
1. 邮箱变更触发时记录原始数据
用户发起邮箱变更请求时,必须通过后端Admin SDK操作,同时记录以下数据到你的数据库(如Firestore):
- 待变更用户的UID
- 变更前的原始邮箱地址
- 变更后的新邮箱地址
- 随机生成的唯一撤销令牌(可以用
crypto模块生成32位随机字符串) - 令牌的过期时间(一般设置为发信后24小时即可)
- 当前变更的状态(
pending待确认/completed已完成/revoked已撤销)
Node.js参考代码:
const crypto = require('crypto'); const admin = require('firebase-admin'); // 处理用户邮箱变更请求 async function handleEmailChange(uid, newEmail) { // 先获取用户原始邮箱 const user = await admin.auth().getUser(uid); const originalEmail = user.email; // 生成撤销令牌 const revokeToken = crypto.randomBytes(32).toString('hex'); const expireAt = Date.now() + 24 * 60 * 60 * 1000; // 24小时后过期 // 写入Firestore await admin.firestore().collection('email_change_requests').add({ uid, originalEmail, newEmail, revokeToken, expireAt, status: 'pending' }); // 生成撤销链接,拼接你的前端页面地址和令牌 const revokeLink = `https://你的应用域名.com/revoke-email-change?token=${revokeToken}`; // 后续将该链接嵌入自定义邮件,发送到用户的原始邮箱即可 }
2. 实现撤销请求的处理逻辑
你需要开发对应的前端页面或后端接口,处理用户点击撤销链接的请求:
- 先校验请求携带的撤销令牌是否存在、是否未过期、对应变更状态是否为
pending - 校验通过后调用Firebase Admin SDK的
updateUser方法将用户邮箱回滚为原始邮箱 - 将数据库中对应变更记录的状态更新为
revoked - 给用户返回撤销成功的提示
Node.js参考代码:
// 处理撤销请求 async function handleRevokeEmailChange(revokeToken) { const reqRef = admin.firestore().collection('email_change_requests').where('revokeToken', '==', revokeToken).limit(1); const reqSnap = await reqRef.get(); if (reqSnap.empty) throw new Error('无效的撤销令牌'); const reqData = reqSnap.docs[0].data(); const reqId = reqSnap.docs[0].id; if (reqData.expireAt < Date.now()) throw new Error('撤销链接已过期'); if (reqData.status !== 'pending') throw new Error('该变更请求已处理,无法撤销'); // 回滚用户邮箱 await admin.auth().updateUser(reqData.uid, { email: reqData.originalEmail }); // 更新请求状态 await admin.firestore().collection('email_change_requests').doc(reqId).update({ status: 'revoked' }); return { success: true, message: '邮箱变更已撤销,已恢复为原始邮箱' }; }
3. 注意事项
- 撤销链接必须发送到用户的原始邮箱地址,不能发送到新邮箱,避免盗号者修改邮箱后自行撤销
- 令牌有效期不要设置过长,建议最长不超过72小时
- 每次发起新的邮箱变更请求时,需要将该用户之前所有未处理的邮箱变更请求状态更新为
expired,避免旧链接生效 - 建议同步记录所有操作日志,便于后续排查问题
内容的提问来源于stack exchange,提问作者Ziyad
相关产品推荐
相关产品推荐

