跳至内容
从 NextAuth.js v4 迁移?阅读 我们的迁移指南.

凭据

要将 Auth.js 与任何外部身份验证机制设置起来,或者使用传统的用户名/电子邮件和密码流,我们可以使用 Credentials 提供商。此提供商旨在将插入登录表单中的任何凭据(例如用户名/密码,但不限于此)转发到您的身份验证服务。

⚠️

自从用户名和密码作为向 Web 应用程序验证和授权用户的首选机制以来,该行业已经取得了长足的进步。因此,如果可能,我们建议使用更现代、更安全的身份验证机制,例如任何 OAuth 提供商电子邮件魔法链接WebAuthn(密钥) 选项。

但是,我们也希望保持灵活性,并支持您认为适合您的应用程序和用例的任何内容,因此我们没有计划删除此提供商。

💡

默认情况下,Credentials 提供商不会在数据库中持久保存数据。但是,您仍然可以在数据库中创建和保存任何数据,您只需要提供必要的逻辑,例如加密密码、添加速率限制、添加密码重置功能等。

Credentials 提供商

首先,让我们在 Auth.js 配置文件中初始化 Credentials 提供商。您需要导入提供商并将其添加到您的 providers 数组中。

./auth.ts
import NextAuth from "next-auth"
import Credentials from "next-auth/providers/credentials"
// Your own logic for dealing with plaintext password strings; be careful!
import { saltAndHashPassword } from "@/utils/password"
 
export const { handlers, signIn, signOut, auth } = NextAuth({
  providers: [
    Credentials({
      // You can specify which fields should be submitted, by adding keys to the `credentials` object.
      // e.g. domain, username, password, 2FA token, etc.
      credentials: {
        email: {},
        password: {},
      },
      authorize: async (credentials) => {
        let user = null
 
        // logic to salt and hash password
        const pwHash = saltAndHashPassword(credentials.password)
 
        // logic to verify if the user exists
        user = await getUserFromDb(credentials.email, pwHash)
 
        if (!user) {
          // No user found, so this is their first attempt to login
          // Optionally, this is also the place you could do a user registration
          throw new Error("Invalid credentials.")
        }
 
        // return user object with their profile data
        return user
      },
    }),
  ],
})

如果您使用的是 TypeScript,您可以 扩展 User 接口 以匹配您的 authorize 回调的响应,因此每当您在其他回调(例如 jwt)中读取用户时,类型都会正确匹配。

登录表单

最后,让我们创建一个简单的登录表单。

./components/sign-in.tsx
import { signIn } from "@/auth"
 
export function SignIn() {
  return (
    <form
      action={async (formData) => {
        "use server"
        await signIn("credentials", formData)
      }}
    >
      <label>
        Email
        <input name="email" type="email" />
      </label>
      <label>
        Password
        <input name="password" type="password" />
      </label>
      <button>Sign In</button>
    </form>
  )
}

验证凭据

始终在服务器端验证凭据,例如利用像 Zod 这样的模式验证库。

npm install zod

接下来,我们将在我们的 auth.ts 配置文件中设置模式和解析,使用 Credentials 提供商上的 authorize 回调。

./lib/zod.ts
import { object, string } from "zod"
 
export const signInSchema = object({
  email: string({ required_error: "Email is required" })
    .min(1, "Email is required")
    .email("Invalid email"),
  password: string({ required_error: "Password is required" })
    .min(1, "Password is required")
    .min(8, "Password must be more than 8 characters")
    .max(32, "Password must be less than 32 characters"),
})
./auth.ts
import NextAuth from "next-auth"
import { ZodError } from "zod"
import Credentials from "next-auth/providers/credentials"
import { signInSchema } from "./lib/zod"
// Your own logic for dealing with plaintext password strings; be careful!
import { saltAndHashPassword } from "@/utils/password"
import { getUserFromDb } from "@/utils/db"
 
export const { handlers, auth } = NextAuth({
  providers: [
    Credentials({
      // You can specify which fields should be submitted, by adding keys to the `credentials` object.
      // e.g. domain, username, password, 2FA token, etc.
      credentials: {
        email: {},
        password: {},
      },
      authorize: async (credentials) => {
        try {
          let user = null
 
          const { email, password } = await signInSchema.parseAsync(credentials)
 
          // logic to salt and hash password
          const pwHash = saltAndHashPassword(password)
 
          // logic to verify if the user exists
          user = await getUserFromDb(email, pwHash)
 
          if (!user) {
            throw new Error("Invalid credentials.")
          }
 
          // return JSON object with the user data
          return user
        } catch (error) {
          if (error instanceof ZodError) {
            // Return `null` to indicate that the credentials are invalid
            return null
          }
        }
      },
    }),
  ],
})
Auth.js © Balázs Orbán 和团队 -2024