Firebase+React Native实现用户申请删号后X天自动删除方案
Firebase + React Native 实现延迟删除账号与登录拦截方案
核心思路
通过Firestore存储删除申请状态 + Cloud Functions定时执行删除 + 登录时状态校验拦截,实现延迟删除+取消删除的完整流程,同时阻断刷积分的漏洞。
1. 数据结构设计(Firestore)
在Firestore中为每个用户文档添加deleteRequest字段,用于跟踪删除状态:
// 用户文档结构示例 { uid: "xxxxxx", email: "user@example.com", points: 100, deleteRequest: { requestedAt: Timestamp.fromDate(new Date()), // 删除申请时间 scheduledDeleteAt: Timestamp.fromDate(new Date(Date.now() + X*24*60*60*1000)), // X天后的时间戳 status: "pending" // 可选值:pending/ cancelled/ completed } }
2. React Native端实现
2.1 用户发起删除申请
用户触发删除申请时,写入Firestore状态并登出:
import { getFirestore, doc, updateDoc } from "firebase/firestore"; import { getAuth, signOut } from "firebase/auth"; const requestAccountDelete = async (uid, delayDays = 30) => { const db = getFirestore(); const scheduledTime = new Date(Date.now() + delayDays * 24 * 60 * 60 * 1000); // 更新用户删除状态 await updateDoc(doc(db, "users", uid), { deleteRequest: { requestedAt: new Date(), scheduledDeleteAt: scheduledTime, status: "pending" } }); // 立即登出用户 await signOut(getAuth()); };
2.2 登录/注册时的拦截与取消删除
在登录成功后立即校验删除状态,根据情况处理:
import { getAuth, onAuthStateChanged } from "firebase/auth"; import { getFirestore, doc, getDoc, updateDoc } from "firebase/firestore"; import { Alert } from "react-native"; const auth = getAuth(); onAuthStateChanged(auth, async (user) => { if (!user) return; const db = getFirestore(); const userDoc = await getDoc(doc(db, "users", user.uid)); if (!userDoc.exists()) return; const deleteRequest = userDoc.data().deleteRequest; // 情况1:处于待删除状态且未到删除时间 if (deleteRequest?.status === "pending" && deleteRequest.scheduledDeleteAt > new Date()) { const shouldCancelDelete = await new Promise((resolve) => { Alert.alert( "账号待删除", "您的账号已申请删除,是否取消删除并恢复使用?", [ { text: "取消删除", onPress: () => resolve(true) }, { text: "继续删除", onPress: () => resolve(false) } ] ); }); if (shouldCancelDelete) { // 更新状态为已取消 await updateDoc(doc(db, "users", user.uid), { "deleteRequest.status": "cancelled" }); // 跳转主页恢复正常使用 } else { // 登出用户,继续执行删除流程 await signOut(auth); } } // 情况2:已到删除时间,直接登出并提示 else if (deleteRequest?.status === "pending" && deleteRequest.scheduledDeleteAt <= new Date()) { Alert.alert("账号即将删除", "您的账号已到期,将被永久删除"); await signOut(auth); } });
2.3 注册防刷处理
注册时先校验邮箱是否存在待删除/已删除记录,避免重复注册刷积分:
import { getFirestore, query, collection, where, getDocs } from "firebase/firestore"; import { Alert } from "react-native"; const checkEmailForDeleteRecord = async (email) => { const db = getFirestore(); const q = query( collection(db, "users"), where("email", "==", email), where("deleteRequest.status", "in", ["pending", "completed"]) ); const snapshot = await getDocs(q); if (!snapshot.empty) { const userDoc = snapshot.docs[0]; const deleteRequest = userDoc.data().deleteRequest; // 如果是pending状态,引导用户登录取消删除 if (deleteRequest.status === "pending") { Alert.alert("账号存在待删除记录", "请登录原账号取消删除申请"); return true; // 阻止注册 } // 如果是已删除,提示重新注册不重置积分 else if (deleteRequest.status === "completed") { Alert.alert("账号已删除", "重新注册将不获得初始积分"); // 后续注册逻辑中跳过初始积分发放 return false; } } return false; // 允许正常注册 };
3. Cloud Functions 实现定时删除
创建定时触发器云函数,每日执行一次,清理到期的待删除账号:
const functions = require("firebase-functions"); const admin = require("firebase-admin"); admin.initializeApp(); exports.cleanupPendingDeletions = functions.pubsub.schedule("every 24 hours").onRun(async (context) => { const db = admin.firestore(); const now = new Date(); // 查询所有待删除且已到时间的用户 const q = db.collection("users") .where("deleteRequest.status", "==", "pending") .where("deleteRequest.scheduledDeleteAt", "<=", now); const snapshot = await q.get(); const deleteTasks = []; snapshot.forEach((doc) => { const uid = doc.id; // 1. 删除认证账号 deleteTasks.push(admin.auth().deleteUser(uid)); // 2. 更新状态为已完成删除 deleteTasks.push(doc.ref.update({ "deleteRequest.status": "completed" })); // 可选:删除关联的其他业务数据(如积分记录、内容等) }); await Promise.all(deleteTasks); functions.logger.log(`处理了${deleteTasks.length/2}个到期删除账号`); return null; });
关键注意事项
- 云函数权限:确保云服务账号拥有
auth.deleteUser权限和Firestore读写权限 - 并发处理:使用Firestore事务处理用户同时发起删除和登录的场景,保证状态更新原子性
- 积分绑定:将积分数据与用户邮箱/手机号绑定,而非仅绑定UID,彻底阻断刷积分漏洞
内容的提问来源于stack exchange,提问作者Chris
相关产品推荐
相关产品推荐

