如何在无已登录用户时调用getDoc()访问Firestore文档
问题分析
调用getDoc()时触发权限错误,根源是当前Firestore安全规则要求所有读写操作必须有已认证用户(request.auth != null),但注册流程中还未完成用户认证,此时没有有效auth凭证,导致权限校验不通过。
解决方案
方案一:调整Firestore安全规则+修正数据逻辑(需控制安全边界)
1. 修正时间存储格式
将CreationDate从字符串改为Firestore Timestamp类型,确保安全规则能正确计算时间差:
// 替换原setDoc中的CreationDate赋值逻辑 await setDoc(doc(db, "Users", userCredential.user.email), { Email: userCredential.user.email, CreationDate: firebase.firestore.Timestamp.now(), // 用Timestamp替代moment生成的字符串 Verified: false, }); // 修正过期判断逻辑 const expired = moment().diff(snap.data().CreationDate.toDate(), "minute");
2. 更新Firestore安全规则
针对Users集合单独配置规则,允许未认证用户查询自身邮箱对应的文档,且仅能删除未验证且过期的文档:
rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { // 其他集合保持原有认证要求 match /{document=**} { allow read, write: if request.auth != null; } // Users集合的特殊规则 match /Users/{email} { // 允许未认证用户读取自身邮箱对应的文档 allow read: if request.resource.id == email; // 仅允许删除未验证且创建时间超过2880分钟的文档 allow delete: if resource.data.Verified == false && (request.time - resource.data.CreationDate) > duration(2880, 'minutes'); } } }
3. 修正代码逻辑错误
原代码中deleteUser(userCredential.user)在createUserWithEmailAndPassword执行前调用,此时userCredential尚未生成,会触发报错。需改为通过邮箱查询用户后删除(前端无此操作权限,建议结合云函数或直接改用方案二)。
方案二:使用Firebase云函数(更安全的推荐方案)
将查询、删除逻辑移至云函数,云函数默认以管理员权限执行,无需调整前端安全规则,同时避免前端篡改校验逻辑:
1. 编写云函数
const functions = require("firebase-functions"); const admin = require("firebase-admin"); admin.initializeApp(); const db = admin.firestore(); exports.cleanupExpiredUnverifiedUsers = functions.https.onCall(async (data, context) => { const { email } = data; if (!email) { throw new functions.https.HttpsError('invalid-argument', '邮箱不能为空'); } const userDocRef = db.collection("Users").doc(email); const docSnap = await userDocRef.get(); if (docSnap.exists()) { const userData = docSnap.data(); const creationDate = userData.CreationDate; const isVerified = userData.Verified; const now = new Date(); const diffMinutes = (now - creationDate.toDate()) / (1000 * 60); if (diffMinutes > 2880 && !isVerified) { // 删除Firestore文档 await userDocRef.delete(); // 删除Auth用户 const userRecord = await admin.auth().getUserByEmail(email); await admin.auth().deleteUser(userRecord.uid); return { success: true, message: "过期未验证账号已清理" }; } } return { success: false, message: "无符合条件的账号需要清理" }; });
2. 前端调用云函数
替换原有的getDoc相关逻辑,改为调用云函数:
import { getFunctions, httpsCallable } from "firebase/functions"; const functions = getFunctions(app); const cleanupExpiredUser = httpsCallable(functions, 'cleanupExpiredUnverifiedUsers'); // 在createUserWithEmailAndPassword前执行清理逻辑 await cleanupExpiredUser({ email }); // 后续执行原注册流程...
内容的提问来源于stack exchange,提问作者hrodric
相关产品推荐
相关产品推荐

