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

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 };

关键说明

  1. 移除jwt回调:database策略下该回调仅在首次登录时执行,后续会话不会触发,依赖它传递数据不可靠
  2. 使用session回调中的user参数:这个user是NextAuth从数据库中关联查询的完整用户实体,包含你定义的所有字段(如role、is_active)
  3. 确保用户实体字段正确:你的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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 09:47:21