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

不修改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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 15:34:54