NextAuth数据库会话策略下Token未定义问题求助
NextAuth database会话策略下回调中token为undefined的解决方法
问题核心原因
当使用database会话策略时,NextAuth的运行逻辑是:
- 用户首次登录时会触发
jwt回调生成初始JWT,但后续会话直接从数据库读取会话记录,不会再调用jwt回调 - 因此
session回调中的token参数会是undefined,因为此时会话数据完全来自数据库,而非JWT解析
切换到jwt策略后数据全为null,大概率是TypeORM实体字段与NextAuth默认映射不匹配,或者JWT回调未正确从数据库拉取用户数据,但既然你需要保留database策略,重点解决前者即可。
解决方案:直接从数据库/会话用户对象获取数据
既然用database策略,无需依赖token传递用户角色等信息,直接在session回调中通过用户ID查询完整数据,或利用NextAuth自动关联的用户对象(前提是你的用户实体包含role字段)。
修改后的代码如下:
import NextAuth from 'next-auth'; import Google from 'next-auth/providers/google'; import Resend from 'next-auth/providers/resend'; import { TypeORMAdapter } from '@auth/typeorm-adapter'; import { AppDataSource, dataSourceOptions } from '@/app/lib/db'; import * as entities from '@/app/lib/entities'; // 初始化数据库连接 if (!AppDataSource.isInitialized) { AppDataSource.initialize() .then(() => console.log('数据库连接初始化完成!')) .catch((err) => { console.error('数据库连接初始化失败:', err); process.exit(1); }); } export const { handlers, signIn, signOut, auth } = NextAuth({ providers: [ Google({ clientId: process.env.GOOGLE_CLIENT_ID!, clientSecret: process.env.GOOGLE_CLIENT_SECRET!, }), Resend({ apiKey: process.env.RESEND_API_KEY!, from: process.env.RESEND_FROM_EMAIL, }), ], adapter: TypeORMAdapter(dataSourceOptions, { entities }), session: { strategy: 'database', }, pages: { signIn: '/login', }, callbacks: { async signIn({ user }): Promise<boolean> { try { const userRepository = AppDataSource.getRepository('users'); await userRepository.update({ id: user.id }, { is_active: true }); console.log(`用户 ${user.email} 已激活`); return true; } catch (error) { console.error('激活用户失败:', error); return false; } }, // 移除database策略下非必需的jwt回调 async session({ session, user }) { // 直接使用从数据库关联查询到的user对象 session.user.id = user.id; session.user.role = user.role; session.user.is_active = user.is_active; // 按需添加其他字段 console.log('Session回调 - 最终会话:', session); return session; }, }, }); export { dataSourceOptions, AppDataSource };
关键说明
- 移除
jwt回调:database策略下该回调仅在首次登录时执行,后续会话不会触发,依赖它传递数据不可靠 - 使用
session回调中的user参数:这个user是NextAuth从数据库中关联查询的完整用户实体,包含你定义的所有字段(如role、is_active) - 确保用户实体字段正确:你的
users实体必须包含role字段,且TypeORM适配器能正确映射
如果用户角色可能在登录后变更,建议在session回调中主动查询最新数据,避免依赖缓存:
async session({ session }) { const userRepository = AppDataSource.getRepository('users'); const dbUser = await userRepository.findOne({ where: { email: session.user.email } }); if (dbUser) { session.user.id = dbUser.id; session.user.role = dbUser.role; session.user.is_active = dbUser.is_active; } return session; }
内容的提问来源于stack exchange,提问作者Kareem.KB
相关产品推荐
相关产品推荐

