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

Firestore安全规则优化:邮箱认证用户创建的权限与用户名校验

安全的Firestore用户规则与用户名唯一性实现方案

一、Firestore规则优化(替代原有宽松规则)

原有规则允许所有用户读取、列出全部用户数据,风险极高。以下是遵循最小权限原则的安全规则:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    // 默认规则:所有操作需先通过身份认证
    match /{document=**} {
      allow read, write: if request.auth != null;
    }

    // 用户集合专属规则
    match /users/{userId} {
      // 仅允许用户读取自己的文档
      allow get: if request.auth.uid == userId;
      // 仅允许用户创建/更新自己的文档,且数据格式合法
      allow create, update: if request.auth.uid == userId && validateUser(request.resource.data);
      // 禁止删除用户文档(可根据需求调整)
      allow delete: if false;

      // 仅允许针对用户名的精确查重查询,限制返回1条结果
      allow list: if request.query.limit <= 1 && request.query.where('name', '==', request.query.name) != null;
    }

    // 验证用户数据格式的辅助函数
    function validateUser(data) {
      return data.name is string && data.name.size() > 0 
             && data.email is string && data.email.matches('^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$');
    }
  }
}

规则核心说明:

  • 身份认证前置:所有操作必须基于已登录用户,拦截未授权访问
  • 数据隔离:用户仅能读写自己UID对应的文档,避免越权操作他人数据
  • 创建/更新校验:强制文档UID与用户认证UID一致,同时验证name、email字段的合法性
  • 受控查询:仅允许用于用户名查重的精确查询,限制返回数量,防止批量爬取用户数据

二、用户名唯一性校验的改进

你当前实现的前端查重仅能提升用户体验,但存在竞态风险(比如两个用户同时查询同一用户名,均通过后提交创建),且前端逻辑可被篡改。必须在服务端做最终校验,推荐使用Firebase云函数实现原子性创建流程:

1. 云函数实现(服务端校验+创建)

const functions = require("firebase-functions");
const admin = require("firebase-admin");
admin.initializeApp();

exports.createUserWithUsername = functions.https.onCall(async (data, context) => {
  const { email, password, name } = data;

  // 服务端二次校验用户名是否存在
  const usernameQuery = await admin.firestore()
    .collection('users')
    .where('name', '==', name)
    .limit(1)
    .get();
  
  if (!usernameQuery.empty) {
    throw new functions.https.HttpsError('already-exists', '用户名已存在');
  }

  // 创建Auth用户
  const userRecord = await admin.auth().createUser({
    email: email,
    password: password,
    displayName: name
  });

  // 写入Firestore用户文档(UID与Auth用户UID绑定)
  await admin.firestore().collection('users').doc(userRecord.uid).set({
    name: name,
    email: email,
    createdAt: admin.firestore.FieldValue.serverTimestamp()
  });

  return { uid: userRecord.uid };
});

2. 前端调用调整

替换原有的直接调用createUserWithEmailAndPassword,改为调用云函数:

// 调用云函数创建用户
final HttpsCallable callable = FirebaseFunctions.instance.httpsCallable('createUserWithUsername');
try {
  final result = await callable.call({
    'email': emailController.text,
    'password': passwordController.text,
    'name': nameController.text,
  });
  String uid = result.data['uid'];
  // 后续逻辑...
} on FirebaseFunctionsException catch (e) {
  if (e.code == 'already-exists') {
    // 提示用户名已存在
  }
  // 处理其他错误
}

改进说明:

  • 服务端强校验:避免前端篡改逻辑导致的用户名重复
  • 原子性操作:确保Auth用户创建与Firestore文档写入同时成功/失败,避免数据不一致
  • 错误标准化:通过云函数的错误码统一处理异常场景

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 16:24:31