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

Next.js App Router中NextAuth Credentials结合argon2报错问题

问题分析

NextAuth v5 的 auth.config.ts 会在边缘运行时环境中执行,而 argon2(包括 @node-rs/argon2)依赖 Node.js 的 node:crypto 模块,边缘环境对 Node.js 核心模块的支持有限,且 webpack 默认不处理 node: 协议的导入,导致出现 UnhandledSchemeError。

解决方案

方案1:将密码验证移至服务端API路由(推荐)

API 路由完全在 Node.js 环境运行,可正常支持 argon2 依赖。

  1. 创建服务端 API 路由 app/api/auth/verify-password/route.ts:
import { NextResponse } from 'next/server'
import { verifyPassword } from '@/utils/hash'

export async function POST(request: Request) {
  const { password, hash } = await request.json()
  
  try {
    const isValid = await verifyPassword(password, hash)
    return NextResponse.json({ isValid })
  } catch (err) {
    return NextResponse.json({ isValid: false }, { status: 500 })
  }
}
  1. 修改 auth.config.ts 中的 authorize 函数,调用该 API:
import type { NextAuthConfig } from 'next-auth'
import Credentials from 'next-auth/providers/credentials'

import { LoginSchema } from './lib/zod'
import { getUserByEmail } from './utils/db'

export default {
  providers: [
    Credentials({
      async authorize(credentials: Partial<Record<string, unknown>>) {
        const validatedFields = LoginSchema.safeParse(credentials)
        if (!validatedFields.success) return null

        const { email, password } = validatedFields.data
        const user = await getUserByEmail(email)
        if (!user || !user.password) return null

        // 调用服务端API验证密码
        const res = await fetch(`${process.env.NEXTAUTH_URL}/api/auth/verify-password`, {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ password, hash: user.password }),
          cache: 'no-store',
        })

        const { isValid } = await res.json()
        if (isValid) return user

        return null
      },
    }),
  ],
} satisfies NextAuthConfig

方案2:配置Webpack处理node:协议(仅Node.js运行时可用)

如果你的项目使用 Node.js 运行时(而非 Edge Runtime),可修改 next.config.js 让 webpack 支持 node: 协议:

/** @type {import('next').NextConfig} */
const nextConfig = {
  webpack: (config) => {
    config.resolve.fallback = {
      ...config.resolve.fallback,
      crypto: require.resolve('crypto-browserify'),
    }
    // 处理node:协议前缀
    config.resolve.plugins = [
      ...(config.resolve.plugins || []),
      {
        apply(resolver) {
          resolver.hooks.resolve.tap('NodeProtocolResolver', (request) => {
            if (request.request.startsWith('node:')) {
              return {
                ...request,
                request: request.request.slice(5),
              }
            }
          })
        },
      },
    ]
    return config
  },
}

module.exports = nextConfig

注意:该方案在 Edge Runtime 环境下无效,因为边缘环境不支持 crypto-browserify 这类模块。

额外说明
  • bcrypt 可用是因为部分版本已兼容边缘环境,或其依赖模块被 webpack 正确处理。
  • @node-rs/argon2 无效的原因和 argon2 一致,均依赖 Node.js 核心模块,无法在边缘环境运行。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 22:13:14