Next.js12 Middleware调用useAuthState出现Invalid hook call错误怎么解决
错误原因
你遇到的报错核心原因是违反了React Hooks的使用规则:
- React Hooks(比如
useAuthState)只能在React函数组件或自定义Hook的函数体内调用 - Next.js 12的Middleware运行在独立的Edge Runtime环境中,属于服务端/边缘侧的普通异步函数,不属于React组件执行上下文,完全不支持调用任何React Hook
解决方案
不要在Middleware中使用客户端React Hook做鉴权,改用ID Token校验的方案实现服务端身份验证,步骤如下:
1. 客户端登录成功后写入ID Token到Cookie
修改login.js的登录逻辑,用户完成Firebase登录后,将获取到的ID Token存入Cookie,供Middleware读取:
import { getAuth, signInWithPopup, GoogleAuthProvider } from "firebase/auth"; function Login() { const signInWithGoogle = async () => { const auth = getAuth(); const provider = new GoogleAuthProvider(); try { const result = await signInWithPopup(auth, provider); const idToken = await result.user.getIdToken(); // 存Cookie,有效期1小时,和Firebase ID Token默认有效期一致 document.cookie = `firebase-token=${idToken}; max-age=3600; path=/`; window.location.href = "/"; } catch (err) { console.error("登录失败:", err); } }; return ( <div> <button onClick={signInWithGoogle}>Sign in with google</button> </div> ); } export default Login;
2. 安装轻量JWT校验库
Firebase Admin SDK不兼容Edge Runtime,选用jose库实现ID Token校验:
npm install jose
3. 重写Middleware鉴权逻辑
替换_middleware.js中的Hook调用逻辑,改为直接校验Cookie中的ID Token有效性:
import { NextResponse } from "next/server"; import * as jose from "jose"; // 替换为你自己的Firebase项目ID const FIREBASE_PROJECT_ID = "your-firebase-project-id"; export async function middleware(req) { const token = req.cookies.get("firebase-token")?.value; const { pathname } = req.nextUrl; // 登录页直接放行,避免循环重定向 if (pathname === "/login") { return NextResponse.next(); } // 无Token直接跳登录页 if (!token) { return NextResponse.redirect("/login"); } try { // 校验Firebase ID Token合法性 const JWKS = jose.createRemoteJWKSet(new URL("https://www.googleapis.com/service_accounts/v1/jwk/securetoken@system.gserviceaccount.com")); await jose.jwtVerify(token, JWKS, { issuer: `https://securetoken.google.com/${FIREBASE_PROJECT_ID}`, audience: FIREBASE_PROJECT_ID, }); // 校验通过放行 return NextResponse.next(); } catch (err) { // 校验失败清除无效Token,跳登录页 const res = NextResponse.redirect("/login"); res.cookies.delete("firebase-token"); return res; } }
可选简化方案
如果不需要边缘侧鉴权,也可以将鉴权逻辑移到客户端根组件_app.js中调用useAuthState,判断用户未登录时跳转登录页,该方案实现更简单,但安全性低于服务端/边缘侧鉴权。
内容的提问来源于stack exchange,提问作者user16949958
相关产品推荐
相关产品推荐

