You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在无已登录用户时调用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 15:20:44