什么是 next-auth
next-auth 是一个专门为 Next.js 设计的、易于使用的、灵活的身份验证库。它简化了为你的应用程序添加身份验证(如登录、注册、登出等)的过程。next-auth 支持多种认证方式,包括通过电子邮件和密码、OAuth 2.0 提供商(如 Google、GitHub、Facebook 等)、以及自定义提供商。
以下是它的一些主要特点:
-
内置 OAuth 提供商
:next-auth 内置支持多个 OAuth 和 OpenID Connect 提供商,使得与第三方服务集成变得简单。 -
会话管理
:提供了简单的 API 来处理用户会话,允许开发者轻松地获取当前用户的会话信息。 -
数据库兼容性
:可以与多种数据库一起使用,以存储用户数据。它支持无头 CMS 和自定义后端。 -
多语言支持
:内置对多语言的支持,可以根据用户的偏好语言显示错误消息和其他文本。 -
自定义页面
:允许创建自定义的登录、注册或错误页面,以便更好地融入应用程序的设计风格。 -
安全默认值
:采用了安全的默认设置,帮助保护应用免受常见的安全问题影响。 -
API 路由
:利用 Next.js 的 API 路由功能来处理身份验证逻辑,这意味着你可以创建自己的端点来进行登录、登出等操作。 -
JWT 或数据库会话
:可以选择使用 JSON Web Tokens (JWT) 进行状态无会话管理,或者选择基于数据库的会话。 -
适配器支持
:对于想要将用户数据持久化到数据库中的情况,next-auth 提供了适配器(adapters),可以方便地与不同的数据库系统进行集成,比如 Prisma、TypeORM 等。
具体步骤
- 安装依赖
pnpm add next-auth@beta
- 设置环境
唯一强制的环境变量是AUTH_SECRET
,这是库用来加密令牌和电子邮件验证散列的随机值。运行以下命令随机生成一个:
npx auth secret
这也会将其添加到本地的 .env
文件中
- 配置
在应用的根目录下创建一个新的auth.ts
文件,包含以下内容:
import NextAuth from "next-auth"
export const { handlers, signIn, signOut, auth } = NextAuth({
providers: [],
})
- 在
/app/api/auth/[...nextauth]/route.ts
下添加路由处理程序:
import { handlers } from "@/auth" // Referring to the auth.ts we just created
export const { GET, POST } = handlers
配置 Github Provider
-
打开 OAuth Apps 页面,点击
New Oauth App
-
填入项目的信息,这里的
Homepage URL
我们可以先填本地开发的地址,等部署上线再改成线上地址,Authorization callback URL
填入https://example.com/api/auth/callback/github
,然后点击Register Application
-
打开刚创建的
Oauth App
,这里可以根据需要设置Oauth App
信息,点击Generate a new client secret
复制密钥
在根目录的
.env
文件中填入刚才复制的密钥
GITHUB_ID= 'xxxxx'
GITHUB_SECRET= 'xxxxxxxxx'
- 打开
/src/auth.ts
文件,配置Github Provider
信息
import NextAuth from "next-auth"
import GitHub from "next-auth/providers/github"
export const { handlers, auth, signIn, signOut } = NextAuth({
providers: [
GitHub({
clientId: process.env.GITHUB_ID,
clientSecret: process.env.GITHUB_SECRET,
})
],
})
会话管理
- 服务器组件 - 登录
import { signIn } from "@/auth.ts"
export function SignIn() {
return (
<form
action={async () => {
"use server"
await signIn("github", { redirectTo: "/dashboard" })
}}
>
<button type="submit">Sign in</button>
</form>
)
}
- 服务器组件 - 退出
import { signOut } from "@/auth.ts"
export function SignOut() {
return (
<form
action={async () => {
"use server"
await signOut()
}}
>
<button type="submit">Sign Out</button>
</form>
)
}
- 客户端组件 - 登录
"use client"
import { signIn } from "next-auth/react"
export function SignIn() {
return (
<button onClick={() => signIn("github", { redirectTo: "/dashboard" })}>
Sign In
</button>
)
}
- 客户端组件 - 退出
"use client"
import { signOut } from "next-auth/react"
export function SignOut() {
return <button onClick={() => signOut()}>Sign Out</button>
}
-
新建一个登录界面,点击登录按钮,就能看到跳转到
Github
授权信息
-
打开控制台,就能看到
session
会话信息,如果没有登录则返回null
适配器 Adapters
在 next-auth 中,适配器(adapters)的主要作用是为会话管理和用户数据持久化提供数据库支持。适配器使得 next-auth 可以与不同的数据库系统进行交互,以便存储和检索用户信息、会话数据以及其他相关的认证信息,下面以 Prisma 为例
- 安装软件包
pnpm add @prisma/client @auth/prisma-adapter
pnpm add prisma --save-dev
- 设置环境变量
DATABASE_URL=postgresql://USER:PASSWORD@HOST:PORT/DATABASE?schema=SCHEMA
- 配置实例
import { PrismaClient } from "@prisma/client"
const globalForPrisma = globalThis as unknown as { prisma: PrismaClient }
export const prisma = globalForPrisma.prisma || new PrismaClient()
if (process.env.NODE_ENV !== "production") globalForPrisma.prisma = prisma
- 打开
/src/auth.ts
文件,配置实例信息
import NextAuth from "next-auth"
import { PrismaAdapter } from "@auth/prisma-adapter"
import { prisma } from "@/prisma"
export const { handlers, auth, signIn, signOut } = NextAuth({
adapter: PrismaAdapter(prisma),
providers: [],
})
- 在根目录
prisma/schema.prisma
创建模型文件
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
generator client {
provider = "prisma-client-js"
}
model User {
id String @id @default(cuid())
name String?
email String @unique
emailVerified DateTime?
image String?
accounts Account[]
sessions Session[]
// Optional for WebAuthn support
Authenticator Authenticator[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model Account {
userId String
type String
provider String
providerAccountId String
refresh_token String?
access_token String?
expires_at Int?
token_type String?
scope String?
id_token String?
session_state String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@id([provider, providerAccountId])
}
model Session {
sessionToken String @unique
userId String
expires DateTime
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model VerificationToken {
identifier String
token String
expires DateTime
@@id([identifier, token])
}
// Optional for WebAuthn support
model Authenticator {
credentialID String @unique
userId String
providerAccountId String
credentialPublicKey String
counter Int
credentialDeviceType String
credentialBackedUp Boolean
transports String?
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@id([userId, credentialID])
}
以上是 PostgreSQL 数据库的模型,如果是其他数据库,请参考:Prisma Adapter
-
在用户登录后,用户的会话信息就会自动保存到数据库:
总结
- 本文只演示了
Github
平台的身份鉴权,其他平台应该也大差不差 - next-auth 还有很多强大的功能需要我们去探索
Github
:next-admin
线上预览地址
:Next Admin