Firebase首次向Realtime Database推送权限被拒、第二次正常如何解决?
异常触发原因
- 核心原因是Firebase Auth状态异步初始化时序问题:首次调用写入函数时,Firebase客户端的Auth状态还未完成与服务端的同步,此时请求携带的auth凭证为空,安全规则判断
auth.uid为null,匹配规则失败返回权限拒绝。第二次调用时Auth状态已经同步完成,携带了有效uid,就能通过规则校验。 - 代码存在隐含问题:代码中混用了数据库实例,开头通过
getDatabase()生成dbRef,但后续update操作使用的db变量未明确初始化,可能导致首次请求的实例未关联当前Auth上下文;另外内层更新totalClasses的update没有加await,属于浮动异步操作,存在时序异常风险。 - 安全规则缺少空校验:规则直接调用
auth.uid,如果auth为null时会直接抛出判断异常,返回权限拒绝,没有提前拦截未登录请求。
修复方案
1. 保证操作在Auth初始化完成后执行
调用writeClass前先通过onAuthStateChanged监听登录状态,确认用户已登录后再触发写入操作,示例代码:
import { getAuth, onAuthStateChanged } from "firebase/auth"; const auth = getAuth(); onAuthStateChanged(auth, (user) => { if (user) { // 只有确认用户登录后再调用writeClass writeClass(/* 传入业务参数 */) } })
2. 修正代码逻辑问题
统一数据库实例,完善异步流程,避免混用async/await和.then/.catch,修正后的代码参考:
// 提前初始化统一的db实例 const db = getDatabase(); export const writeClass = async ( courseId, topicName, classIntro, youtubeLinkId, classNoteLink ) => { try { // 读取totalClasses const totalClassesSnap = await get(child(ref(db), `Courses/${courseId}/totalClasses`)); const totalClassesNum = parseInt(totalClassesSnap.val()) + 1; // 写入班级信息 await update( ref(db, `Courses/${courseId}/classes/${totalClassesNum}`), { classIntro, topicName, youtubeLinkId, classNoteLink, } ); // 同步更新totalClasses,加await保证执行完成 await update(ref(db, `Courses/${courseId}`), { totalClasses: totalClassesNum, }); console.log("Section added"); return true; } catch (error) { console.log(error.message); return error.message; } };
3. 完善安全规则
增加auth非空前置判断,避免空指针判断异常:
".write" : "auth != null && root.child('specialUsers').child(auth.uid).child('is_admin').val() === true"
内容的提问来源于stack exchange,提问作者Marzuk Rahman Adi
相关产品推荐
相关产品推荐

