Firebase/Firestore安全规则失效及resource未定义问题求助
Firestore安全规则问题解决指南
错误原因分析
你遇到的resource is undefined错误,核心原因是集合级别的list查询(比如collection.get())中不存在resource对象:
resource仅在单个文档操作(如获取单个文档、更新、删除)时可用,代表目标文档的当前数据;- 批量读取集合时,Firestore规则无法提前获取每个文档的
resource,因此直接引用会触发未定义错误。
同时,你当前的方案存在致命安全漏洞:未使用Firebase认证,导致安全规则无法可靠识别请求发起者的身份——任何人只要知道其他用户的username,就能构造请求访问其数据,完全无法实现“用户仅能读写自己的progress集合”的需求。
推荐解决方案:使用Firebase自定义认证
这是生产环境下的标准安全方案,通过自定义认证关联用户身份,让规则能精准识别操作主体:
1. 编写云函数验证用户名密码并生成自定义Token
创建云函数,负责验证用户输入的用户名密码,通过后生成Firebase自定义认证Token:
const functions = require("firebase-functions"); const admin = require("firebase-admin"); admin.initializeApp(); exports.login = functions.https.onCall(async (data, context) => { const { username, password } = data; // 查询匹配的用户文档 const userSnapshot = await admin.firestore() .collection("users") .where("username", "==", username) .where("password", "==", password) .get(); if (userSnapshot.empty) { throw new functions.https.HttpsError("invalid-argument", "用户名或密码错误"); } const userDoc = userSnapshot.docs[0]; // 生成自定义Token,用用户文档ID作为Auth的uid const token = await admin.auth().createCustomToken(userDoc.id); return { token, userId: userDoc.id }; });
2. 客户端通过云函数登录
在Ionic/Angular客户端调用云函数获取Token,完成Firebase认证:
import { AngularFireAuth } from '@angular/fire/compat/auth'; import { Functions, httpsCallable } from '@angular/fire/functions'; constructor(private afAuth: AngularFireAuth, private functions: Functions) {} async login(username: string, password: string) { const loginFn = httpsCallable(this.functions, 'login'); const result = await loginFn({ username, password }); const { token } = result.data as { token: string }; // 用自定义Token完成登录 await this.afAuth.signInWithCustomToken(token); }
3. 设置安全规则
现在可以通过request.auth.uid识别用户身份,精准控制数据访问权限:
service cloud.firestore { match /databases/{database}/documents { // 仅允许用户读取自己的用户文档 match /users/{userId} { allow read: if request.auth.uid == userId; // 禁止直接写入用户文档(避免篡改敏感信息,如需修改可通过云函数) allow write: if false; } // 允许用户读写自己的progress子集合 match /users/{userId}/progress/{progressDoc} { allow read, write: if request.auth.uid == userId; } } }
测试用临时方案(不安全,仅用于本地调试)
如果暂时不想引入云函数,可临时开放符合查询条件的读取权限,但请注意这会导致用户数据暴露风险:
service cloud.firestore { match /databases/{database}/documents { match /users/{userDoc} { // 仅允许携带username和deployment条件的查询 allow read: if request.query.where('username', '==', resource.data.username) && request.query.where('deployment', '==', resource.data.deployment); allow write: if false; } // 临时开放progress子集合权限(测试用) match /users/{userDoc}/progress/{progressDoc} { allow read, write: if true; } } }
内容的提问来源于stack exchange,提问作者Rick Ford
相关产品推荐
相关产品推荐

