如何在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
相关产品推荐
相关产品推荐

