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

注册流程中未认证用户无需Cloud Functions读取Firestore数据的方法

解决方案:无Cloud Functions的React Native Expo Firebase注册安全校验

核心思路:调整注册顺序,利用Auth身份做安全校验

未认证状态下直接读取Firestore确实存在恶意枚举用户名/邮箱的风险。我们可以调整注册流程,先创建Firebase Auth用户,再依托该用户的临时认证身份完成唯一性校验与文档写入,同时通过Firestore安全规则严格限制数据访问权限。

调整后的注册流程

  1. 用户填写表单并通过本地格式校验
  2. 调用createUserWithEmailAndPassword创建Auth用户
  3. 用新生成的Auth用户身份,查询Firestore检查用户名/邮箱是否已存在
  4. 若存在:删除刚创建的Auth用户,返回错误提示给用户
  5. 若不存在:以Auth用户UID为文档ID,在Users集合写入用户信息

Firestore安全规则配置

配置规则确保只有已认证用户可访问唯一性校验查询,且仅能写入自身UID对应的文档:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /users/{userId} {
      // 仅允许已认证用户查询目标用户名/邮箱的存在性,避免恶意枚举
      allow read: if request.auth != null 
                  && (request.query.where[0].value == resource.data.username 
                      || request.query.where[0].value == resource.data.email);
      // 仅允许用户创建自身UID对应的文档,且文档需不存在
      allow create: if request.auth != null 
                    && request.auth.uid == userId 
                    && !exists(/databases/$(database)/documents/users/$(userId));
    }
  }
}

React Native代码实现示例

import { getAuth, createUserWithEmailAndPassword, deleteUser } from "firebase/auth";
import { getFirestore, query, where, collection, getDocs, setDoc, doc } from "firebase/firestore";

const auth = getAuth();
const db = getFirestore();

const signUp = async (username, email, password) => {
  try {
    // 第一步:创建Auth用户
    const userCredential = await createUserWithEmailAndPassword(auth, email, password);
    const currentUser = userCredential.user;

    // 检查用户名唯一性
    const usernameQuery = query(collection(db, "users"), where("username", "==", username));
    const usernameSnapshot = await getDocs(usernameQuery);
    if (!usernameSnapshot.empty) {
      await deleteUser(currentUser);
      throw new Error("用户名已被注册");
    }

    // 检查邮箱唯一性(可选:Firebase Auth本身会校验邮箱唯一性,若业务允许同一邮箱多账号则保留)
    const emailQuery = query(collection(db, "users"), where("email", "==", email));
    const emailSnapshot = await getDocs(emailQuery);
    if (!emailSnapshot.empty) {
      await deleteUser(currentUser);
      throw new Error("邮箱已被注册");
    }

    // 写入用户文档
    await setDoc(doc(db, "users", currentUser.uid), {
      username,
      email,
      createdAt: new Date()
      // 其他需要存储的用户信息
    });

    return { success: true, message: "注册成功" };
  } catch (error) {
    // 处理Auth原生错误,比如邮箱已被占用
    if (error.code === "auth/email-already-in-use") {
      return { success: false, message: "邮箱已被注册" };
    }
    return { success: false, message: error.message };
  }
};

额外注意事项

  • 本地表单校验要提前完成(比如邮箱格式、用户名长度限制),减少不必要的Auth请求
  • 删除Auth用户时,需确保用户处于登录状态(刚创建的用户默认登录,无需额外处理)

内容的提问来源于stack exchange,提问作者Damjan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 02:46:00