NextAuth Session未查询自定义username字段问题求助
问题
我在用户模型中添加了username字段,但调用getServerSession(authOptions)时生成的SQL查询并未包含该字段:
select "session"."sessionToken", "session"."userId", "session"."expires", "user"."id", "user"."name", "user"."email", "user"."emailVerified", "user"."image" from "session" inner join "user" on "user"."id" = "session"."userId" where "session"."sessionToken" = $1
但用Drizzle直接执行select().from(users)查询时,能正常获取到username字段:
select "id", "name", "email", "emailVerified", "image", "username" from "user"
我的AuthOptions配置如下:
import NextAuth, { AuthOptions } from "next-auth" import GoogleProvider from "next-auth/providers/google"; import { DrizzleAdapter } from "@auth/drizzle-adapter" import { db } from "@/db/connection"; import { User } from "@/db/schema"; export const authOptions: AuthOptions = { adapter: DrizzleAdapter(db), providers: [ GoogleProvider({ clientId: process.env.GOOGLE_CLIENT_ID!, clientSecret: process.env.GOOGLE_CLIENT_SECRET! }), ], callbacks: { async session({ session, user }) { session.user.username = (user as User).username; return session } } } const handler = NextAuth(authOptions); export { handler as GET, handler as POST }
解决方案
NextAuth的Drizzle适配器默认仅查询User表中预设的字段(id、name、email、emailVerified、image),自定义的username不在默认查询范围内,因此getServerSession返回的user对象中不包含该字段,直接在session回调中赋值无法拿到正确值。
提供两种解决方式:
方式1:在session回调中主动查询完整用户信息
修改session回调逻辑,通过Drizzle手动查询用户数据获取username:
// 需先导入users表schema和eq操作符 import { users } from "@/db/schema"; import { eq } from "drizzle-orm"; // ...其他配置不变 callbacks: { async session({ session, user }) { const fullUser = await db.select().from(users).where(eq(users.id, user.id)).get(); if (fullUser) { session.user.username = fullUser.username; } return session; } }
方式2:重写Drizzle适配器的查询方法
自定义适配器,扩展默认查询字段,让session查询自动包含username:
import { DrizzleAdapter } from "@auth/drizzle-adapter"; import { db } from "@/db/connection"; import { users, sessions } from "@/db/schema"; import { eq } from "drizzle-orm"; // 基于默认适配器重写getSessionAndUser方法 const customAdapter = DrizzleAdapter(db); customAdapter.getSessionAndUser = async (sessionToken) => { const result = await db .select({ session: sessions, user: { id: users.id, name: users.name, email: users.email, emailVerified: users.emailVerified, image: users.image, username: users.username, // 添加自定义字段 }, }) .from(sessions) .innerJoin(users, eq(users.id, sessions.userId)) .where(eq(sessions.sessionToken, sessionToken)) .get(); if (!result) return null; const { session, user } = result; return { session: { ...session, expires: new Date(session.expires) }, user, }; }; // 在authOptions中使用自定义适配器 export const authOptions: AuthOptions = { adapter: customAdapter, providers: [ GoogleProvider({ clientId: process.env.GOOGLE_CLIENT_ID!, clientSecret: process.env.GOOGLE_CLIENT_SECRET! }), ], callbacks: { async session({ session, user }) { session.user.username = (user as User).username; return session; } } }
说明
方式1实现简单,适合仅需添加少量自定义字段的场景;方式2一劳永逸,所有通过getServerSession获取的用户数据都会包含自定义字段,适合多自定义字段的场景。
内容的提问来源于stack exchange,提问作者user3747260
相关产品推荐
相关产品推荐

