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

如何在NextAuth.js中扩展User类型以存储用户profile属性?

在NextAuth.js的Session中添加Profile属性的解决方案

我需要在NextAuth.js的session对象中添加profile属性,用于根据用户角色做条件渲染。通过后端获取token后,我请求登录用户数据并尝试存入session,但只能获取NextAuth.js自带的name和email属性,无法添加profile属性。

相关代码

src\app\api\auth[...nextauth]\route.ts

import { Client, createClient } from 'ldapjs'
import { NextAuthOptions } from 'next-auth'
import NextAuth from 'next-auth/next'
import CredentialsProvider from 'next-auth/providers/credentials'

const client: Client = createClient({
  url: process.env.ACTIVE_DIRECTORY_URL || ''
})

const handler = NextAuth({
  providers: [
    CredentialsProvider({
      name: 'LDAP',
      credentials: {
        username: { label: 'username', type: 'text', placeholder: '' },
        password: { label: 'Password', type: 'password' }
      },
      async authorize(credentials) {
        if (!credentials?.username || !credentials?.password) {
          return null
        }

        return new Promise((resolve, reject) => {
          client.bind(
            credentials.username + '@lorem-ipum.net',
            credentials.password,
            (error) => {
              if (error) {
                console.error(error)
                reject(error)
              } else {
                resolve({
                  email: credentials.username,
                  password: credentials.password
                })
              }
            }
          )
        })
      }
    })
  ],
  callbacks: {
    async jwt({ token, user, session }) {
      if (user) {
        const tokenResult = await fetch(
          process.env.BACKEND_URL + '/user/login',
          {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({
              userName: user.email,
              password: user.password
            }),
            cache: 'no-store'
          }
        ).then(async (response) => {
          return await response.json()
        })

        token.accessToken = tokenResult.token

        user = await fetch(process.env.BACKEND_URL + '/user/userLogged', {
          method: 'GET',
          headers: { Authorization: 'Bearer ' + tokenResult.token }
        }).then(async (response) => {
          return await response.json()
        })
      }

      return { ...token, ...user, ...session }
    },
    async session({ session, user }) {
      return { ...session, ...user }
    }
  },
  pages: {
    signIn: '/login'
  },
  session: {
    strategy: 'jwt'
  }
} as NextAuthOptions)

export { handler as GET, handler as POST }

@types\next-auth.d.ts

/* eslint-disable @typescript-eslint/no-unused-vars */
import NextAuth, { DefaultSession } from 'next-auth'

declare module 'next-auth' {
  interface Session extends DefaultSession {
    user: {
      profile: string
    }
  }
}

src\app\layout.tsx

import '@radix-ui/themes/styles.css'
import { getServerSession } from 'next-auth'
import './globals.css'

export default async function RootLayout({
  login
}: {
  login: React.ReactNode
}) {
  const session = await getServerSession()

  console.log(session?.user)

  return (
    <html lang="en">
      <body>
        {session?.user ? (
          <>
            {/* Here would be the conditional rendering by user type ("profile" property) */}
          </>
        ) : (
          login
        )}
      </body>
    </html>
  )
}

解决方案

1. 修正JWT与Session回调逻辑

使用JWT session策略时,自定义数据需要先存入JWT token,再同步到session中。同时你误用了JWT回调的参数,修正如下:

callbacks: {
  async jwt({ token, user }) {
    if (user) {
      const tokenResult = await fetch(
        process.env.BACKEND_URL + '/user/login',
        {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({
            userName: user.email,
            password: user.password
          }),
          cache: 'no-store'
        }
      ).then(res => res.json())

      token.accessToken = tokenResult.token

      // 获取用户数据并提取profile存入token
      const userProfile = await fetch(process.env.BACKEND_URL + '/user/userLogged', {
        method: 'GET',
        headers: { Authorization: 'Bearer ' + tokenResult.token },
        cache: 'no-store'
      }).then(res => res.json())
      
      token.profile = userProfile.profile
    }

    return token
  },
  async session({ session, token }) {
    // 将token中的profile同步到session.user
    if (session.user) {
      session.user.profile = token.profile
    }
    return session
  }
},

2. 修正TypeScript类型定义

原定义直接覆盖了session.user,会丢失默认属性,需改为扩展类型:

/* eslint-disable @typescript-eslint/no-unused-vars */
import NextAuth, { DefaultSession } from 'next-auth'

declare module 'next-auth' {
  interface Session extends DefaultSession {
    user: DefaultSession['user'] & {
      profile: string
    }
  }

  // 扩展JWT类型,让TS识别自定义属性
  interface JWT {
    profile: string
    accessToken?: string
  }
}

3. 验证结果

修改完成后,在layout.tsx中打印session?.user即可看到profile属性,后续可基于该属性实现角色条件渲染。

内容的提问来源于stack exchange,提问作者Isac Freire Bezerra

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 07:02:45