不修改Prisma Adapter,如何为AuthJS用户添加必填唯一handler字段?
问题描述
需要在不修改Prisma Adapter本身的前提下实现以下需求:
- 用户创建账户时,添加必填且唯一的String类型字段
handler - 用户登录时自动生成随机唯一的
handler值
此前尝试通过createUser事件实现,但未成功。相关代码如下:
Prisma模型
model User { id String @id @default(cuid()) name String? email String? @unique emailVerified DateTime? image String? handler String @unique <------- accounts Account[] sessions Session[] }
NuxtAuthHandler代码
import GithubProvider from 'next-auth/providers/github' import EmailProvider from 'next-auth/providers/email' import { PrismaAdapter } from '@next-auth/prisma-adapter' import { PrismaClient } from '@prisma/client' import { NuxtAuthHandler } from '#auth' import { generateFromEmail } from "unique-username-generator"; const prisma = new PrismaClient() export default NuxtAuthHandler({ adapter: PrismaAdapter(prisma), session: { strategy: 'database', maxAge: 30 * 24 * 60 * 60, updateAge: 24 * 60 * 60 }, pages: { signIn: '/auth/login' }, secret: process.env.AUTH_SECRET, providers: [ // @ts-expect-error GithubProvider.default({ clientId: process.env.AUTH_GITHUB_CLIENT_ID, clientSecret: process.env.AUTH_GITHUB_CLIENT_SECRET, allowDangerousEmailAccountLinking: true, }), // @ts-expect-error EmailProvider.default({ server: { host: process.env.EMAIL_SERVER_HOST, port: process.env.EMAIL_SERVER_PORT, auth: { user: process.env.EMAIL_SERVER_USER, pass: process.env.EMAIL_SERVER_PASSWORD } }, from: process.env.EMAIL_FROM, allowDangerousEmailAccountLinking: true, }) ], events: { createUser: async (user) => { console.log(user) try { if (!user.handler && user.email) { console.log('creating handler') const handler = generateFromEmail(user.email, 4) console.log({handler}) const existingUser = await prisma.user.findUnique({ where: { email: user.email } }) if (existingUser) { console.log({existingUser}) await prisma.user.update({ where: { id: user.id }, data: { handler } }) } } } catch (err) { console.log(err) } } } })
可行实现方案
问题根源
之前的createUser事件无法生效,是因为Prisma Adapter在创建用户时会直接向数据库插入记录,但handler是必填字段,此时没有传入值会触发数据库报错,导致用户创建流程直接失败,createUser事件根本不会被执行。
解决方案:封装自定义Prisma Adapter
不需要修改官方Adapter源码,通过封装重写createUser方法,在用户创建前就生成并注入handler字段:
步骤1:编写自定义Adapter
import { PrismaAdapter } from '@next-auth/prisma-adapter' import { generateFromEmail } from 'unique-username-generator' import { PrismaClient } from '@prisma/client' const prisma = new PrismaClient() const CustomPrismaAdapter = (prisma) => { const adapter = PrismaAdapter(prisma) const originalCreateUser = adapter.createUser // 重写createUser方法,提前生成handler adapter.createUser = async (user) => { if (!user.handler && user.email) { let handler = generateFromEmail(user.email, 4) // 循环检查handler唯一性,避免重复 let existingHandler = await prisma.user.findUnique({ where: { handler } }) while (existingHandler) { handler = `${generateFromEmail(user.email, 4)}-${Math.random().toString(36).slice(2, 5)}` existingHandler = await prisma.user.findUnique({ where: { handler } }) } // 将handler注入到用户创建参数中 user.handler = handler } // 调用原方法完成用户创建 return originalCreateUser(user) } return adapter } export default CustomPrismaAdapter
步骤2:在NuxtAuthHandler中使用自定义Adapter
替换原有的PrismaAdapter(prisma)为自定义Adapter:
import GithubProvider from 'next-auth/providers/github' import EmailProvider from 'next-auth/providers/email' import { NuxtAuthHandler } from '#auth' import { PrismaClient } from '@prisma/client' import CustomPrismaAdapter from './path-to-your-custom-adapter' // 替换为自定义Adapter的路径 const prisma = new PrismaClient() export default NuxtAuthHandler({ adapter: CustomPrismaAdapter(prisma), // 使用自定义Adapter session: { strategy: 'database', maxAge: 30 * 24 * 60 * 60, updateAge: 24 * 60 * 60 }, pages: { signIn: '/auth/login' }, secret: process.env.AUTH_SECRET, providers: [ // @ts-expect-error GithubProvider.default({ clientId: process.env.AUTH_GITHUB_CLIENT_ID, clientSecret: process.env.AUTH_GITHUB_CLIENT_SECRET, allowDangerousEmailAccountLinking: true, }), // @ts-expect-error EmailProvider.default({ server: { host: process.env.EMAIL_SERVER_HOST, port: process.env.EMAIL_SERVER_PORT, auth: { user: process.env.EMAIL_SERVER_USER, pass: process.env.EMAIL_SERVER_PASSWORD } }, from: process.env.EMAIL_FROM, allowDangerousEmailAccountLinking: true, }) ] })
关键说明
- 提前生成
handler并注入,确保数据库插入时字段非空,避免创建失败 - 增加唯一性检查逻辑,防止
generateFromEmail生成重复值 - 完全基于官方Adapter封装,无需修改源码,符合需求
内容的提问来源于stack exchange,提问作者NuoNuo LeRobot
相关产品推荐
相关产品推荐

