React+Firebase项目如何在cookie设置完成后更新authContext及登录状态
问题根因
你遇到的getLoggedIn提前调用问题,本质是createUser函数内部没有正确串联异步流程:外层的await只能等待你显式返回的Promise完成,原有代码里的user.getIdToken()、axios.post都属于嵌套的异步任务,既没有做await处理,也没有将Promise返回给外层,导致await createUser()只等了Firebase创建用户的步骤完成,不等后续接口请求、服务端写入Cookie的流程结束就提前resolve了,自然getLoggedIn会拿不到最新的Cookie。
修复步骤
1. 重写createUser函数,补齐所有异步等待
建议统一用async/await语法,避免混用.then链式调用导致遗漏Promise等待,修改后代码如下:
export const createUser = async (props) => { console.log("New User Creation Initiated", props); const { email, password } = props; try { // 等待Firebase创建用户完成 const { user } = await firebase.auth().createUserWithEmailAndPassword(email, password); console.log("createUserWithEmailAndPassword", user); // 等待获取用户token完成 const tokenId = await user.getIdToken(); const userObject = { tokenId }; // 关键:等待axios请求完成,服务端返回后Cookie才会写入浏览器 await axios.post(`${domain}/auth`, userObject); return; } catch (err) { console.log("New User Creation Error: ", err); // 抛出错误让外层调用的catch可以捕获到异常 throw err; } };
2. 优化调用逻辑,统一异步写法
避免await和.then混用,风格更统一也不容易出问题:
const { getLoggedIn, loggedIn } = useContext(AuthContext); const register = async (e) => { e.preventDefault(); const registerData = { email, password, passwordVerify, }; try { await createUser(registerData); // 此时createUser所有流程已走完,Cookie已经写入,直接调用校验即可 await getLoggedIn(); } catch (err) { console.log(err); } };
3. 可选:服务端代码优化(非必须但更稳妥)
原有Express接口里写入用户数据到Firestore的操作没有加等待,可能出现用户数据还没入库就返回的情况,修改后如下:
router.post("/", async (req, res) => { console.log("---User signup initiated---"); try { const { tokenId } = req.body; console.log("tokenId passed from frontend: ", tokenId); const decodedToken = await admin.auth().verifyIdToken(tokenId); const { email, uid } = decodedToken; console.log("Fetched UID: ", uid); console.log("Fetched email: ", email); const Users = db.collection("users"); // 等待用户数据写入完成再往下执行 await Users.doc(`${uid}`).set({ email: email, posts: [], }); console.log("---jwt signing initiated---"); const token = jwt.sign( { user: { email, uid }, }, process.env.JWT_SECRET ); console.log("token log: ", token); return res .cookie("token", token, { httpOnly: true, sameSite: "none", secure: true, }) .send(); } catch (err) { console.log(err); return res.sendStatus(500); } });
其他疑问解答
- 不需要监听Cookie变更:只要异步流程串联正确,
createUser返回时Cookie已经写入浏览器,直接调用getLoggedIn即可,监听Cookie属于冗余操作,没有必要。 - 整体实现思路没有问题:用httpOnly Cookie存JWT是当前比较安全的前端鉴权方案,只要修复异步等待的问题就能正常运行。
内容的提问来源于stack exchange,提问作者Matt
相关产品推荐
相关产品推荐

