next-auth对接Firebase遇问题:开启安全规则后无法读写数据
我在Next.js应用中配置了NextAuth的Google登录提供商,已设置Web客户端ID与密钥,但使用Google登录后,Firebase控制台未创建用户,也无法识别已登录用户。关闭Firebase安全规则时可正常读写Firestore文档,但设置allow read, write: if request.auth != null;规则后则无法操作。曾尝试使用FirestoreAdapter但未成功,想了解是遗漏了配置还是该方案暂不适合生产环境?
现有配置代码
[...nextauth].js
import NextAuth from "next-auth"; import GoogleProvider from "next-auth/providers/google"; import { firebaseConfig } from "../../../src/lib/firebase"; // import { FirestoreAdapter } from "@next-auth/firebase-adapter"; export default NextAuth({ providers: [ GoogleProvider({ clientId: process.env.GOOGLE_WEB_CLIENT_ID, clientSecret: process.env.GOOGLE_WEB_CLIENT_SECRET, }), ], pages: { signIn: "/auth/sign-in", }, // 目前暂未启用适配器 // adapter: FirestoreAdapter({ // apiKey: "", // authDomain: "", // projectId: "", // storageBucket: "", // messagingSenderId: "", // appId: "", // measurementId: "", // Optional emulator config (see below for options) // emulator: {}, // }), // ... });
登录组件代码
{Object.values(providers).map((provider) => ( <div key={provider.name}> <button className={styles.signInButton} onClick={() => signIn(provider.id, { callbackUrl: "/" })} > 用{provider.name}登录 </button> </div> ))}
Firestore文档创建测试代码
const docRef = await addDoc(collection(db, "tests"), { fullName: values.fullName, createdAt: serverTimestamp(), });
1. 根本问题:两个独立的身份系统
NextAuth的登录状态和Firebase Auth完全不互通——你用NextAuth完成Google登录后,Firebase完全不知道用户已登录,所以request.auth始终为null,触发安全规则拦截。而FirestoreAdapter只是用来存储NextAuth的用户数据到Firestore,不会同步到Firebase Auth用户池,也无法让Firebase识别NextAuth的登录状态。
2. 可行解决方向
方案一:登录后同步到Firebase Auth
在NextAuth登录成功后,用Google返回的ID Token去Firebase Auth创建/关联用户,让两边身份同步:
import { getAuth, signInWithCredential, GoogleAuthProvider } from "firebase/auth"; import { app } from "../../../src/lib/firebase"; export default NextAuth({ // ... 原有配置 callbacks: { async jwt({ token, account }) { // 首次登录时获取Google的id_token并同步到Firebase Auth if (account?.provider === "google" && account.id_token) { const auth = getAuth(app); const credential = GoogleAuthProvider.credential(account.id_token); const userCredential = await signInWithCredential(auth, credential); // 把Firebase用户ID存入token备用 token.firebaseUid = userCredential.user.uid; } return token; }, async session({ session, token }) { // 将Firebase UID同步到前端session session.user.firebaseUid = token.firebaseUid; return session; } }, });
方案二:直接用Firebase Auth处理登录
如果核心依赖Firebase生态,放弃NextAuth的Google提供商,直接用Firebase Auth的登录能力更省心:
- 前端调用
signInWithPopup(auth, new GoogleAuthProvider())完成登录 - 自动同步到Firebase Auth用户池,Firestore的
request.auth会正常识别 - 若需NextAuth的session管理,可将Firebase Auth的token传入NextAuth做二次封装
方案三:自定义Firestore安全规则适配NextAuth(不推荐生产)
若坚持用NextAuth身份,需在请求Firestore时携带NextAuth的session token,通过Cloud Functions编写验证函数,在安全规则中调用验证。但这种方式复杂度高,安全性不如官方Auth系统,不建议生产环境使用。
3. FirestoreAdapter的正确定位
FirestoreAdapter只是NextAuth的数据存储适配器——它把NextAuth的用户、会话等数据存在你的Firestore中,方便管理NextAuth的用户数据,但和Firebase Auth没有关联,无法解决request.auth的鉴权问题。
内容的提问来源于stack exchange,提问作者BenjaminK

