首次渲染出现Firebase权限不足问题,附规则及Hook代码求助
问题:首次登录后Firestore权限错误及自定义Hook排查
问题背景
首次登录后页面首次渲染时,会弹出“missing or insufficient permissions”权限错误,刷新页面后功能恢复正常。推测是认证状态未及时完成验证导致的问题。当把Firestore规则改为allow read: if true;时所有功能正常,说明问题出在if request.auth != null;的规则判断逻辑上。
当前Firestore规则
service cloud.firestore { match /databases/{database}/documents { // Users match /users/{user} { allow read, update: if request.auth != null; allow create, delete: if request.auth != null && request.auth.token.admin == true; } // folders match /folders/{folder} { allow read, create, delete, update: if request.auth != null && request.auth.token.admin == true; // allow read: if true; } } }
补充信息:控制台报错指向的自定义Hook
import { auth } from '../../firebase'; function useAdminStatus() { const [isAdmin, setIsAdmin] = useState(false); useEffect(() => { const checkAdmin = async () => { const idTokenResult = await auth?.currentUser?.getIdTokenResult(); if (idTokenResult?.claims?.admin) { setIsAdmin(true); } else { setIsAdmin(false); } }; checkAdmin(); }); return { isAdmin }; } export default useAdminStatus;
问题分析与解决方案
1. 自定义Hook存在的问题
- 没有依赖数组:
useEffect未指定依赖项,会导致组件每次渲染都重复执行checkAdmin函数,不仅浪费资源,还可能引发状态更新混乱。 - 未监听Auth状态变化:首次登录完成前
auth.currentUser可能为null,直接调用getIdTokenResult()会得到undefined,导致isAdmin始终为false,进而触发Firestore权限错误。 - 缺少错误处理:
checkAdmin是异步函数,但未添加错误捕获逻辑,若获取ID Token失败会静默报错,难以排查问题。
2. 修复后的自定义Hook代码
import { auth, onAuthStateChanged } from '../../firebase'; function useAdminStatus() { const [isAdmin, setIsAdmin] = useState(false); const [isAuthLoaded, setIsAuthLoaded] = useState(false); // 标记认证状态是否加载完成 useEffect(() => { // 监听用户认证状态变化 const unsubscribe = onAuthStateChanged(auth, async (user) => { if (user) { try { const idTokenResult = await user.getIdTokenResult(); setIsAdmin(!!idTokenResult?.claims?.admin); } catch (error) { console.error('获取管理员权限失败:', error); setIsAdmin(false); } } else { setIsAdmin(false); } setIsAuthLoaded(true); // 认证状态加载完成,更新标记 }); // 组件卸载时清理订阅 return () => unsubscribe(); }, []); return { isAdmin, isAuthLoaded }; } export default useAdminStatus;
3. 页面组件的配套处理
在使用Firestore数据的组件中,必须等待isAuthLoaded为true后再发起请求,避免在认证状态未就绪时触发权限错误:
import useAdminStatus from './useAdminStatus'; import { getDocs, collection } from 'firebase/firestore'; import { db } from '../../firebase'; function FolderList() { const { isAdmin, isAuthLoaded } = useAdminStatus(); useEffect(() => { if (isAuthLoaded) { // 认证状态就绪后,安全发起Firestore请求 const fetchFolders = async () => { const querySnapshot = await getDocs(collection(db, 'folders')); // 处理获取到的文件夹数据 }; fetchFolders(); } }, [isAuthLoaded, isAdmin]); // 认证未完成时显示加载状态 if (!isAuthLoaded) { return <div>加载中...</div>; } return <div>文件夹列表内容</div>; }
4. Firestore规则说明
当前规则逻辑本身没有问题,只要确保请求发起时request.auth已存在即可。通过上述Hook的修复,保证只有在Auth状态完全加载完成后才发起Firestore请求,就能彻底解决首次渲染时的权限错误。
内容的提问来源于stack exchange,提问作者psych0groov3
相关产品推荐
相关产品推荐

