技术篇:身份验证-NextAuth
Next.js实战教程 - 系列文章
学习目标:为应用接入用户登录功能
NextAuth.js 简介 #
随着现代Web应用的复杂性不断增加,用户认证和授权变得至关重要。NextAuth.js 是一个开源的用户认证库,支持多种身份验证方式,包括 OAuth、邮件登录、凭证登录等。它专为 Next.js 设计,但也可以集成到其他 React 应用中。通过其丰富的配置选项和内置的安全特性,开发者可以快速搭建一个功能强大的认证系统。
核心概念与功能 #
Provider(认证提供者) #
Provider 是 NextAuth.js 用于实现身份验证的核心,NextAuth.js 支持多种认证提供者,如 OAuth Providers:Google, Facebook, GitHub, Twitter 等第三方服务,Email Provider:基于邮箱的登录方式,以及 Credentials Provider:允许开发者自定义基于用户名和密码的登录系统。
Session 管理 #
NextAuth.js 支持两种 Session 管理策略,通过 JWT(JSON Web Token)或基于数据库的会话管理来保持用户的登录状态。JWT Session 为默认策略,本文的演示也给予默认策略。
JWT(JSON Web Token) #
NextAuth.js 支持无状态身份验证,使用 JWT 存储会话信息。
数据库集成 #
为了保存用户信息和会话数据,NextAuth.js 可以与各种数据库(如 MongoDB、PostgreSQL、MySQL)集成。
Cookies #
成功登录后,NextAuth 会在你的浏览器中设置一组 Cookies。
Callbacks(回调函数) #
NextAuth.js 提供了多种回调函数,允许开发者在身份验证的不同阶段执行自定义逻辑。这些回调函数包括:
jwt
:在生成或更新 JWT 时调用。session
:在生成或更新会话时调用。signIn
:在用户尝试登录时调用,可以控制是否允许登录。redirect
:控制登录或注销后的重定向行为。
内置安全机制 #
提供了多种内置的安全机制,例如 CSRF 保护、JWT 加密,确保身份验证流程的安全性。
实战示例 #
项目初始化 #
npx create-next-app@latest
✔ What is your project named? … example-auth
✔ Would you like to use TypeScript? … No / Yes
✔ Would you like to use ESLint? … No / Yes
✔ Would you like to use Tailwind CSS? … No / Yes
✔ Would you like to use `src/` directory? … No / Yes
✔ Would you like to use App Router? (recommended) … No / Yes
✔ Would you like to customize the default import alias (@/*)? … No / Yes
安装 Next-Auth #
首先需要安装 NextAuth.js 和相关依赖:
yarn add next-auth
创建 GitHub OAuth 应用 #
在集成 GitHub 登录之前,你需要创建一个 GitHub OAuth 应用来获取 Client ID
和 Client Secret
。
- 登录 GitHub Developer Settings。
- 在 “OAuth Apps” 下,点击 “New OAuth App”。
- 填写必要的信息:
- Application name:你的应用名称。
- Homepage URL:如
http://localhost:3000
(本地开发时使用)。 - Authorization callback URL:
http://localhost:3000/api/auth/callback/github
(NextAuth.js 默认的 GitHub 回调 URL)。
- 创建应用后,你将获得
Client ID
和Client Secret
。
基本配置 #
在 app/api
目录下创建 auth/[...nextauth]/route.js
文件:
// app/api/auth/[...nextauth]/route.js
import NextAuth from "next-auth";
import GitHubProvider from "next-auth/providers/github";
const handler = NextAuth({
providers: [
GitHubProvider({
clientId: process.env.GITHUB_ID,
clientSecret: process.env.GITHUB_SECRET,
}),
],
session: {
strategy: "jwt",
},
callbacks: {
async session({ session, token }) {
session.user.id = token.sub; // 将用户ID附加到会话中
return session;
},
},
});
export { handler as GET, handler as POST };
这个 API 路由将处理 GitHub 的 OAuth 身份验证过程。NextAuth.js 默认会处理 GET 和 POST 请求,因此需要导出 GET
和 POST
。
设置环境变量 #
将 GitHub 应用的 Client ID
和 Client Secret
配置到 .env
文件中:
GITHUB_CLIENT_ID=your-github-client-id
GITHUB_CLIENT_SECRET=your-github-client-secret
NEXTAUTH_URL=http://localhost:3000 # 本地开发时使用
确保用你从 GitHub 获取的 Client ID
和 Client Secret
替换相应的占位符。
生成和配置 NEXTAUTH_SECRET
#
你可以通过运行以下命令生成一个随机的 32 字节的密钥:
openssl rand -base64 32
生成的密钥可能像这样:
base64encodedsecretstring==
将 NEXTAUTH_SECRET
配置到 .env
文件中:
NEXTAUTH_SECRET=base64encodedsecretstring==
GITHUB_CLIENT_ID=your-github-client-id
GITHUB_CLIENT_SECRET=your-github-client-secret
NEXTAUTH_URL=http://localhost:3000
NEXTAUTH_SECRET
,用于加密会话令牌(JWT)等。
在客户端使用 useSession
管理会话
#
在 Next.js 13 中,使用 useSession
在页面或组件中显示用户的登录状态,并提供登录/注销按钮。
在 app/page.js
文件中,添加以下代码:
// app/page.js;
"use client";
import { useSession, signIn, signOut } from "next-auth/react";
export default function HomePage() {
const { data: session, status } = useSession();
if (status === "loading") {
return <p>Loading...</p>;
}
return (
<div className="p-10">
{!session ? (
<>
<p>Not signed in</p>
<button onClick={() => signIn("github")}>Sign in with GitHub</button>
</>
) : (
<>
<p>Signed in as {session.user.email}</p>
<img
className="w-[100px] h-[100px]"
src={session.user.image}
alt={session.user.name}
style={{ borderRadius: "50%" }}
/>
<button onClick={() => signOut()}>Sign out</button>
</>
)}
</div>
);
}
useSession
钩子获取当前用户的会话信息。- 如果用户未登录,会显示一个 GitHub 登录按钮。
- 登录后,显示用户的邮箱和头像,同时提供注销按钮。
配置 next-auth
提供的 Provider
#
由于 App Router 是完全异步的,SessionProvider
必须包裹在根布局中。你需要在 app/layout.js
中配置 SessionProvider
以提供会话上下文。
- 在
app
目录创建Provider.js
:
"use client";
import { SessionProvider } from "next-auth/react";
export function Provider({ children }) {
return <SessionProvider>{children}</SessionProvider>;
}
- 在
app/layout.js
文件中添加Providers
:
// app/layout.js
import "./globals.css";
import { Provider } from "./Provider";
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>
<Provider>{children}</Provider>
</body>
</html>
);
}
SessionProvider
确保会话信息可以在应用中的所有组件中访问。
运行应用 #
最后,在终端中运行 Next.js 应用:
yarn dev
访问 http://localhost:3000
,你会看到登录界面。点击 “Sign in with GitHub”,并使用 GitHub 账号进行登录。
回调与安全配置(可选) #
你可以在 callbacks
选项中进一步自定义登录过程,比如获取用户的更多 GitHub 信息:
callbacks: {
async signIn({ user, account, profile }) {
return profile.email.endsWith("@example.com") // 仅允许特定域名的 GitHub 用户登录
},
async jwt({ token, account }) {
if (account) {
token.accessToken = account.access_token
}
return token
},
async session({ session, token }) {
session.accessToken = token.accessToken
return session
},
}
总结 #
NextAuth.js 是一个功能强大且灵活的认证解决方案,适合各种规模的应用。从简单的 OAuth 集成到复杂的自定义认证逻辑,它几乎可以满足所有的需求。通过本文我们正式接入登录功能。
参考 #
https://github.com/nextauthjs/next-auth
https://authjs.dev/concepts/session-strategies
https://next-auth.js.org/configuration/options#nextauth_secret