Firestore规则中用户已登录但request.auth仍为null的问题排查
Firebase Firestore规则中request.auth为null导致权限拒绝问题
问题详情
用户已完成登录,但Firestore安全规则中的request.auth始终返回null,触发权限拒绝错误。未设置安全规则时,认证和数据获取流程完全正常;设置规则后出现以下错误:
FirebaseError: [code=permission-denied]: Missing or insufficient permissions.
将规则改为allow read, write: if true;或allow read, write: if request.auth == null;时,数据请求恢复正常。
相关代码
Firestore安全规则
rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { match /{document=**} { allow read, write: if request.auth != null; } } }
自定义Auth Hook
import { useEffect, useState } from "react"; import { auth } from "./config"; import { onAuthStateChanged } from "firebase/auth"; import { getUserData } from "../actions/userActions"; function useAuth() { const [user, setUser] = useState<any>(undefined); const [uid, setUid] = useState<any>(undefined); const [firstName, setFirstName] = useState<any>(undefined); const [lastName, setLastName] = useState<any>(undefined); const [displayName, setDisplayName] = useState<any>(undefined); const [email, setEmail] = useState<any>(undefined); const [phone, setPhone] = useState<any>(undefined); const [address, setAddress] = useState<any>(undefined); const [role, setRole] = useState<any>(undefined); useEffect(() => { const fetchUserData = async (user: any) => { let userData = await getUserData(user.uid); if (userData) { setUid(userData.uid); setFirstName(userData.firstName); setLastName(userData.lastName); setDisplayName(userData.displayName); setEmail(userData.email); setPhone(userData.phone); setAddress(userData.address); setRole(userData.role); } }; const unsubscribe = onAuthStateChanged(auth, (user) => { if (user) { setUser(user); fetchUserData(user); } else { setUser(undefined); setUid(undefined); setFirstName(undefined); setLastName(undefined); setDisplayName(undefined); setEmail(undefined); setPhone(undefined); setAddress(undefined); setRole(undefined); } }); return () => unsubscribe(); }); return { user, uid, firstName, lastName, displayName, email, phone, address, role, }; } export default useAuth;
getUserData函数
export const getUserData = async (uid: string) => { try { const snapshot = await getDoc(doc(firestore, "users", uid)); if (snapshot) return snapshot.data(); else return undefined; } catch (e) { console.error("Error at 'getUserData': " + e); return undefined; } };
客户端使用方式
const {user} = useAuth()
在组件中渲染:
<p>{user.uid}</p>
已尝试的解决方法
- 修改规则为
request.auth.uid != null - 清除浏览器缓存
- 使用Firebase规则测试平台验证规则
- 添加条件确保登录完成后再发起数据请求
可能的原因与解决方案
1. Auth与Firestore实例未关联同一Firebase App
确保Firestore和Auth是通过同一个Firebase App实例初始化的,避免因实例不匹配导致认证信息无法同步:
// config.js 示例 import { initializeApp } from "firebase/app"; import { getAuth } from "firebase/auth"; import { getFirestore } from "firebase/firestore"; const firebaseConfig = { /* 你的项目配置 */ }; const app = initializeApp(firebaseConfig); export const auth = getAuth(app); export const firestore = getFirestore(app); // 必须使用同一个app实例
2. 认证令牌未完成同步
onAuthStateChanged触发时,用户对象已存在,但Firestore可能还未获取到最新的认证令牌。可以等待令牌就绪后再请求数据:
修改Hook中的fetchUserData函数:
const fetchUserData = async (user: any) => { await user.getIdTokenResult(); // 等待令牌刷新完成 let userData = await getUserData(user.uid); // 后续状态更新代码不变 };
3. 规则测试平台使用不当
在Firebase控制台的规则测试工具中,需手动模拟已认证用户:
- 选择“已认证”选项
- 输入与实际登录用户一致的
uid - 测试读取
/users/{uid}路径的权限,确认规则是否通过
4. 缓存的旧认证令牌导致异常
尝试登出后重新登录,强制刷新认证令牌:
// 在测试环境中临时调用 auth.signOut().then(() => { // 重新登录逻辑 });
也可以清除浏览器的本地存储和缓存,避免旧令牌干扰。
5. 匿名登录或自定义认证的令牌问题
如果使用匿名登录或自定义认证:
- 匿名登录:确保规则中允许匿名用户(若需要),或切换为常规认证方式测试
- 自定义认证:检查自定义令牌是否包含有效的
uid,且签名正确
内容的提问来源于stack exchange,提问作者Lätizia S
相关产品推荐
相关产品推荐

