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

Auth.js中auth()方法返回空user对象的原因及会话关联问题

问题

在Next.js项目中用Auth.js的Credentials Provider实现登录,功能能正常运行,但登录后调用auth()返回的session里user是空对象:

// 未登录
const session = await auth();
console.log(session)
// null

// 登录后
const session = await auth();
console.log(session)
// { user: {}, expires: '2024-07-28T14:03:13.208Z' }

调用外部登录API返回的数据结构如下:

{
  result: { status_code: 0, status: 'Ok', message: 'Sign in' },
  payload: {
    data: {
      auth: [Object], // Bearer令牌
      refresh_token: [Object], // 刷新令牌
      user: [Object], // 用户信息
      project: [Object] // 用户关联项目信息
    }
  }
}

需要明确:

  1. 为什么session里的user是空对象?正确形态应该是什么样?
  2. API返回的auth、refresh_token、user、project字段和Auth.js会话的关联关系,以及如何绑定?
  3. API返回的user与session里的user对象的对应方式。

当前使用的auth.ts代码:

import NextAuth from "next-auth";
import CredentialsProvider from "next-auth/providers/credentials";

export const {
  handlers: { GET, POST },
  auth,
  signIn,
  signOut
} = NextAuth({
  session: {
    strategy: "jwt",
  },
  providers: [
    CredentialsProvider({
      async authorize(credentials){
        try {
          const login = await fetch(`https://some_project/login`, {
            method: "POST",
            headers: {
              "Content-Type": "application/json",
            },
            body: JSON.stringify(credentials),
          });
          const user = await login.json();
          console.log(user);
          return user;
        } catch (error) {
          throw new Error("")
        }
      }
    })
  ]
})

解答

1. session.user为空的原因

你在authorize回调里直接返回了整个API响应对象,但Auth.js默认会从返回值中提取id、name、email这类标准字段来构建session的user对象。而你的用户信息嵌套在payload.data.user里,外层对象没有符合要求的标准字段,导致Auth.js无法提取有效数据,最终生成空的user对象。

2. 正确的代码修改方案

因为使用的是jwt会话策略,需要通过jwt和session两个回调定制token和session内容,把API返回的有效数据关联进去:

import NextAuth from "next-auth";
import CredentialsProvider from "next-auth/providers/credentials";

export const {
  handlers: { GET, POST },
  auth,
  signIn,
  signOut
} = NextAuth({
  session: {
    strategy: "jwt",
  },
  providers: [
    CredentialsProvider({
      async authorize(credentials){
        try {
          const loginRes = await fetch(`https://some_project/login`, {
            method: "POST",
            headers: {
              "Content-Type": "application/json",
            },
            body: JSON.stringify(credentials),
          });
          
          if (!loginRes.ok) throw new Error("登录失败");
          
          const apiData = await loginRes.json();
          // 提取API返回的核心数据(根据实际字段名调整)
          const { auth, refresh_token, user, project } = apiData.payload.data;
          
          // 返回需要存入JWT的关键数据,该返回值会传给jwt回调
          return {
            accessToken: auth.token, // Bearer令牌内容
            refreshToken: refresh_token.token, // 刷新令牌内容
            userInfo: user, // 完整用户信息
            projectInfo: project // 用户关联项目信息
          };
        } catch (error) {
          throw new Error("登录失败,请检查账号密码");
        }
      }
    })
  ],
  callbacks: {
    // 定制JWT存储的内容
    async jwt({ token, user }) {
      // user仅在首次登录时存在,来自authorize的返回值
      if (user) {
        token.accessToken = user.accessToken;
        token.refreshToken = user.refreshToken;
        token.user = user.userInfo;
        token.project = user.projectInfo;
      }
      return token;
    },
    // 定制返回给前端的session内容
    async session({ session, token }) {
      // 将JWT中的自定义数据同步到session
      session.user = token.user as any;
      session.project = token.project as any;
      session.accessToken = token.accessToken as string;
      // 注意:refreshToken不要暴露给前端,仅存于JWT中
      return session;
    }
  }
})

3. API字段与会话的关联说明

  • auth(Bearer令牌):存入JWT的accessToken字段,后续请求外部API时用该令牌做身份认证。
  • refresh_token:存入JWT的refreshToken字段,用于令牌过期时调用API刷新accessToken(需额外实现刷新逻辑)。
  • user:直接赋值给session的user对象,前端调用auth()就能拿到完整的用户信息,比如session.user.id、session.user.username等(根据API返回的user结构调整)。
  • project:可存入session的project字段,方便前端直接获取用户关联的项目信息。

4. 修改后的session形态

登录后调用auth()会返回类似如下结构:

{
  user: { id: 123, username: "xxx", email: "xxx@xxx.com", ... }, // API返回的完整user内容
  project: { id: 456, name: "项目名", ... }, // API返回的完整project内容
  accessToken: "Bearer xxxxxx", // Bearer令牌
  expires: "2024-07-28T14:03:13.208Z"
}

内容的提问来源于stack exchange,提问作者Jim

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 20:04:51