豆包:https://www.doubao.com/chat/38428026830768386
环境说明:
npm install next@16 next-auth@5 bcryptjs
npm install -D @types/bcryptjs
新建文件:app/api/auth/[...nextauth]/route.ts
import NextAuth, { NextAuthOptions } from "next-auth";
import CredentialsProvider from "next-auth/providers/credentials";
// 模拟用户库(实际用数据库)
const mockUser = {
id: "1",
name: "张三",
email: "zhangsan@test.com",
password: "123456",
};
export const authOptions: NextAuthOptions = {
providers: [
CredentialsProvider({
name: "Credentials",
credentials: {
username: { label: "用户名", type: "text" },
password: { label: "密码", type: "password" },
},
async authorize(credentials) {
// 表单提交校验
if (!credentials?.username || !credentials?.password) return null;
// 模拟登录校验
if (
credentials.username === mockUser.name &&
credentials.password === mockUser.password
) {
return {
id: mockUser.id,
name: mockUser.name,
email: mockUser.email,
};
}
return null;
},
}),
],
session: {
strategy: "jwt", // 必须 jwt,Credentials 不支持数据库 session
},
callbacks: {
// JWT 回调:把用户信息存入 token
async jwt({ token, user }) {
if (user) {
token.id = user.id;
token.name = user.name;
}
return token;
},
// Session 回调:把 token 信息暴露给前端
async session({ session, token }) {
if (token) {
session.user.id = token.id as string;
session.user.name = token.name as string;
}
return session;
},
},
pages: {
signIn: "/login", // 自定义登录页
},
};
const handler = NextAuth(authOptions);
export { handler as GET, handler as POST };
新建:app/providers.tsx
"use client";
import { SessionProvider } from "next-auth/react";
export default function AuthProviders({
children,
}: {
children: React.ReactNode;
}) {
return <SessionProvider>{children}</SessionProvider>;
}
修改根布局 app/layout.tsx
import type { Metadata } from "next";
import AuthProviders from "./providers";
export const metadata: Metadata = {
title: "Next16 Credentials 登录案例",
};
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="zh">
<body>
<AuthProviders>{children}</AuthProviders>
</body>
</html>
);
}
新建:app/login/page.tsx
"use client";
import { signIn } from "next-auth/react";
import { useRouter } from "next/navigation";
import { useState } from "react";
export default function LoginPage() {
const router = useRouter();
const [error, setError] = useState("");
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
const formData = new FormData(e.target as HTMLFormElement);
const username = formData.get("username") as string;
const password = formData.get("password") as string;
// 调用 next-auth 登录
const res = await signIn("credentials", {
username,
password,
redirect: false,
});
if (res?.error) {
setError("用户名或密码错误");
} else {
router.push("/"); // 登录成功跳首页
router.refresh();
}
};
return (
<div style={{ padding: "2rem" }}>
<h1>表单登录</h1>
{error && <p style={{ color: "red" }}>{error}</p>}
<form onSubmit={handleSubmit}>
<div>
<label>用户名:</label>
<input name="username" defaultValue="张三" required />
</div>
<div style={{ marginTop: "0.5rem" }}>
<label>密码:</label>
<input name="password" type="password" defaultValue="123456" required />
</div>
<button type="submit" style={{ marginTop: "1rem" }}>
登录
</button>
</form>
</div>
);
}
app/page.tsx
"use client";
import { useSession, signOut } from "next-auth/react";
export default function Home() {
const { data: session, status } = useSession();
if (status === "loading") return <p>加载中...</p>;
return (
<div style={{ padding: "2rem" }}>
<h1>首页 - 客户端获取登录信息</h1>
{session ? (
<>
<p>✅ 已登录,用户名:{session.user?.name}</p>
<button onClick={() => signOut({ callbackUrl: "/login" })}>
退出登录
</button>
<p>
<a href="/api/user-info">查看后端获取用户信息</a>
</p>
</>
) : (
<p>❌ 未登录,请 <a href="/login">去登录</a></p>
)}
</div>
);
}
新建:app/api/user-info/route.ts
import { getServerSession } from "next-auth/next";
import { authOptions } from "../auth/[...nextauth]/route";
export async function GET() {
// 服务端获取 session
const session = await getServerSession(authOptions);
if (!session) {
return Response.json({ isLogin: false, msg: "未登录" }, { status: 401 });
}
return Response.json({
isLogin: true,
username: session.user?.name,
userId: session.user?.id,
});
}
npm run devhttp://localhost:3000/login张三,密码:123456/api/user-info 后端返回登录状态和用户名useSession() 判断登录、拿用户名getServerSession(authOptions) 判断登录、拿用户名signIn / signOut