You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 17:42:47