NextAuth中首次登录用户重定向并传递Google用户信息的问题
问题
我用NextAuth实现了Google OAuth登录,在signIn异步回调里通过getUser查询数据库判断是否首次登录,首次登录就重定向到/sign-up页面,但在这个页面里获取到的session是null。我不想用NextAuth的适配器,因为它会创建多张表,我想尽量减少数据库存储的数据量。
技术栈:Next.js App Router(14.2.16)、NextAuth v5.0.0(beta)
auth.ts 代码:
export const { handlers, auth } = NextAuth({ providers: [ GoogleProvider({ clientId: process.env.GOOGLE_CLIENT_ID as string, clientSecret: process.env.GOOGLE_CLIENT_SECRET as string, }), ], callbacks: { async signIn({ user, account, profile }) { if (account?.provider === "google") { const isNewUSer = await getUser({ uuid: profile.sub }); if (!isNewUSer) { return true; } } return "/sign-up"; }, async jwt({ token, account, profile }) { if (account && profile) { token.sub = profile.sub; token.name = profile.name; token.email = profile.email; token.isNewUser = false; } return token; }, async session({ session, token }) { if (session.user) { session.user.id = token.sub; session.user.isNewUser = token.isNewUser as boolean; } return session; }, }, pages: { signIn: "/login", newUser: "/sign-up", }, });
/sign-up/page.tsx 代码:
import { auth } from "@/auth"; export default async function SignUp() { const session = await auth(); console.log("sign-up session = ", session); // 已Google登录,但session为null return ( <div> <form> {/* 该表单提交操作会将昵称、uuid、邮箱等用户信息存储到数据库 */} <input type="text" placeholder="Enter your Nickname" name="nickname" /> <button>Submit</button> </form> </div> ); }
需要解决的问题:如何在重定向新用户到/sign-up页面时,传递从Google获取到的用户信息?
解决方案
问题核心是返回/sign-up时NextAuth还未完成session创建,导致新用户访问该页面拿不到session。以下是无需适配器的解决思路:
1. 修改signIn回调,临时存储Google用户信息到Cookie
先安装cookie库处理Cookie:
npm install cookie
然后修改auth.ts的signIn回调,将Google返回的用户信息加密后存入临时Cookie,再重定向:
import { serialize } from 'cookie'; // ... 其他代码 async signIn({ user, account, profile }) { if (account?.provider === "google") { const existingUser = await getUser({ uuid: profile.sub }); if (existingUser) { return true; } // 新用户:加密存储Google用户信息到临时Cookie const tempUserInfo = serialize( 'temp_google_user', JSON.stringify({ sub: profile.sub, name: profile.name, email: profile.email, }), { httpOnly: true, secure: process.env.NODE_ENV === 'production', sameSite: 'lax', maxAge: 60 * 5, // 5分钟过期,降低安全风险 path: '/sign-up', // 仅允许/sign-up页面访问 } ); // 返回带Cookie的重定向响应 return { redirect: { destination: '/sign-up', permanent: false, }, headers: { 'Set-Cookie': tempUserInfo, }, }; } return true; }
2. 在/sign-up页面读取临时Cookie获取用户信息
修改/sign-up/page.tsx,从Cookie中解析临时存储的Google用户信息:
import { cookies } from 'next/headers'; import { redirect } from 'next/navigation'; export default async function SignUp() { const cookieStore = cookies(); const tempUserCookie = cookieStore.get('temp_google_user'); if (!tempUserCookie) { // 非登录跳转来的用户直接重定向到登录页 redirect('/login'); } const googleUser = JSON.parse(tempUserCookie.value); console.log('Google用户信息:', googleUser); // 可拿到sub、name、email等字段 // 表单提交逻辑:将Google信息和昵称存入数据库 const handleSubmit = async (formData: FormData) => { const nickname = formData.get('nickname') as string; await fetch('/api/sign-up', { method: 'POST', body: JSON.stringify({ nickname, uuid: googleUser.sub, email: googleUser.email, name: googleUser.name, }), headers: { 'Content-Type': 'application/json', }, }); // 提交成功后删除临时Cookie,并重定向触发Session创建 cookieStore.delete('temp_google_user'); redirect('/'); }; return ( <div> <form action={handleSubmit}> <input type="text" placeholder="Enter your Nickname" name="nickname" required /> <button type="submit">Submit</button> </form> </div> ); }
3. 完善JWT回调逻辑(可选)
调整JWT回调,动态判断用户是否为新用户,确保后续Session正常生成:
async jwt({ token, account, profile }) { if (account && profile) { const existingUser = await getUser({ uuid: profile.sub }); token.sub = profile.sub; token.name = profile.name; token.email = profile.email; token.isNewUser = !existingUser; // 不存在则标记为新用户 } return token; }
内容的提问来源于stack exchange,提问作者이준희
相关产品推荐
相关产品推荐

