
文章目录1. 环境准备安装依赖2. 数据库设计 (MySQL)3. 数据库连接4. 配置 NextAuth.js5. 注册用户接口6. 登录页面 (App Router)7. 注册页面8. 保护 API 路由9. 登录成功页面10. 前端展示登录状态11. ✅ 完成效果 和 鉴权流程图1. 环境准备Node.js ≥ 18Next.js 15MySQL 数据库安装依赖# 初始化 Next.js 15 项目npx create-next-applatest my-nextauth-app--tscdmy-nextauth-app# 安装 MySQL 依赖npminstallmysql2# 安装 Auth.js / NextAuthnpminstallnext-auth注意NextAuth.js 从 v5 开始演进为Auth.jsAPI 与 v4 基本类似但更现代化。下面示例使用NextAuth v5 方式。2. 数据库设计 (MySQL)创建一个用户表users用于存储账号和密码这里示例用 bcrypt 加密。CREATEDATABASEnextauth_demo;USEnextauth_demo;CREATETABLEusers(idINTAUTO_INCREMENTPRIMARYKEY,nameVARCHAR(255)NOTNULL,emailVARCHAR(255)NOTNULLUNIQUE,passwordVARCHAR(255)NOTNULL,created_atTIMESTAMPDEFAULTCURRENT_TIMESTAMP);如图3. 数据库连接创建一个数据库工具文件app/lib/mysql.ts// app/lib/mysql.tsimportmysqlfrommysql2/promise;exportconstdbmysql.createPool({host:process.env.MYSQL_HOST,user:process.env.MYSQL_USER,password:process.env.MYSQL_PASSWORD,database:process.env.MYSQL_DATABASE});在项目根目录新建.env文件并配置MYSQL_HOSTlocalhost MYSQL_USERroot MYSQL_PASSWORD123456 MYSQL_DATABASEnextauth_demo NEXTAUTH_SECRET5c2e7a9d3f8b1k6m4n0p2q7r9t8v3w5x7y1z9a4s6d8f0g2h4j6k8l0m2n4p6q8r NEXTAUTH_URLhttp://localhost:30004. 配置 NextAuth.js在Next.js 15 App Router下API 路由在app/api/auth/[...nextauth]/route.ts// app/api/auth/[...nextauth]/route.tsimportNextAuthfromnext-auth;importCredentialsProviderfromnext-auth/providers/credentials;import{db}from../../../lib/mysql;importbcryptfrombcryptjs;exportconstauthOptions{session:{strategy:jwt// 修改为 JWT 策略与 Credentials 兼容},providers:[CredentialsProvider({name:Credentials,credentials:{email:{label:Email,type:text},password:{label:Password,type:password}},asyncauthorize(credentials){console.log(Authorize credentials:,credentials);try{if(!credentials?.email||!credentials?.password)returnnull;const[rows]:anyawaitdb.query(SELECT * FROM users WHERE email ?,[credentials.email]);console.log(Query result:,rows);constuserrows[0];if(!user){console.log(No user found);returnnull;}constisValidawaitbcrypt.compare(credentials.password,user.password);if(!isValid){console.log(Invalid password);returnnull;}return{id:user.id,name:user.name,email:user.email};}catch(err){console.error(Authorize error:,err);throwerr;// 让你能在终端看到具体错误}}})],pages:{signIn:/auth/signin},secret:process.env.NEXTAUTH_SECRET};consthandlerNextAuth(authOptions);export{handlerasGET,handlerasPOST};5. 注册用户接口在app/api/auth/register/route.ts创建注册接口// app/api/auth/register/route.tsimport{db}from/lib/mysql;importbcryptfrombcryptjs;import{NextResponse}fromnext/server;exportasyncfunctionPOST(req:Request){const{name,email,password}awaitreq.json();if(!name||!email||!password){returnNextResponse.json({error:Missing fields},{status:400});}consthashedPasswordawaitbcrypt.hash(password,10);try{awaitdb.query(INSERT INTO users (name, email, password) VALUES (?, ?, ?),[name,email,hashedPassword]);returnNextResponse.json({message:User registered});}catch(error:any){if(error.codeER_DUP_ENTRY){returnNextResponse.json({error:Email already exists},{status:400});}returnNextResponse.json({error:Server error},{status:500});}}6. 登录页面 (App Router)在app/auth/signin/page.tsxuse client;import{signIn}fromnext-auth/react;import{useState}fromreact;import{useRouter}fromnext/navigation;exportdefaultfunctionSignInPage(){const[email,setEmail]useState();const[password,setPassword]useState();constrouteruseRouter();consthandleSubmitasync(e:React.FormEvent){e.preventDefault();constresawaitsignIn(credentials,{redirect:false,email,password});if(res?.ok)router.push(/dashboard);elsealert(Invalid credentials);};return(form onSubmit{handleSubmit}input typeemailplaceholderEmailvalue{email}onChange{(e)setEmail(e.target.value)}/input typepasswordplaceholderPasswordvalue{password}onChange{(e)setPassword(e.target.value)}/button typesubmitLogin/button/form);}如图所示7. 注册页面app/auth/register/page.tsxuse client;import{useState}fromreact;import{useRouter}fromnext/navigation;exportdefaultfunctionRegisterPage(){const[name,setName]useState();const[email,setEmail]useState();const[password,setPassword]useState();constrouteruseRouter();consthandleSubmitasync(e:React.FormEvent){e.preventDefault();constresawaitfetch(/api/auth/register,{method:POST,body:JSON.stringify({name,email,password}),headers:{Content-Type:application/json}});constdataawaitres.json();if(res.ok)router.push(/auth/signin);elsealert(data.error);};return(form onSubmit{handleSubmit}input typetextplaceholderNamevalue{name}onChange{(e)setName(e.target.value)}/input typeemailplaceholderEmailvalue{email}onChange{(e)setEmail(e.target.value)}/input typepasswordplaceholderPasswordvalue{password}onChange{(e)setPassword(e.target.value)}/button typesubmitRegister/button/form);}注册成功如下所示8. 保护 API 路由创建app/api/protected/route.tsimport{getServerSession}fromnext-auth;import{authOptions}from../auth/[...nextauth]/route;import{NextResponse}fromnext/server;exportasyncfunctionGET(req:Request){constsessionawaitgetServerSession(authOptions);if(!session)returnNextResponse.json({error:Unauthorized},{status:401});returnNextResponse.json({message:Protected content,user:session.user});}它的作用是示例一个需要登录后才能访问的 API。如果客户端直接访问/api/protectedNextAuth会检查当前请求里带的 Cookie (session)。如果没登录没有 session就返回 { “error”: “Unauthorized” }。如果已经登录会返回用户信息。 用途你可以用它来写后台接口比如 获取用户订单、获取个人资料 等。这类 API 需要鉴权不能随便访问。如下图所示9. 登录成功页面app/dashboard/page.tsximport{getServerSession}fromnext-auth;import{authOptions}from../api/auth/[...nextauth]/route;import{redirect}fromnext/navigation;exportdefaultasyncfunctionDashboardPage(){constsessionawaitgetServerSession(authOptions);if(!session)redirect(/auth/signin);return(divh1Welcome{session.user?.name}/h1pEmail:{session.user?.email}/p/div);}登录成功会跳转到/dashboard页面如下所示10. 前端展示登录状态你可以在app/layout.tsx中全局显示登录状态import{getServerSession}fromnext-auth;import{authOptions}from./api/auth/[...nextauth]/route;importLinkfromnext/link;exportdefaultasyncfunctionRootLayout({children}:{children:React.ReactNode}){constsessionawaitgetServerSession(authOptions);return(htmlbodyheader{session?(spanHi,{session.user?.name}/spanLink href/api/auth/signoutLogout/Link/):(Link href/auth/signinSign In/LinkLink href/auth/registerRegister/Link/)}/header{children}/body/html);}11. ✅ 完成效果 和 鉴权流程图完成效果注册用户 → 自动加密密码存入 MySQL登录 → NextAuth 验证 Session Cookie受保护页面/API → 未登录自动跳转或返回 401全局显示登录状态鉴权流程图Session Cookie(next-auth.session-token)MySQL 数据库NextAuth API/api/auth/[...nextauth]前端页面(app/)用户(浏览器)Session Cookie(next-auth.session-token)MySQL 数据库NextAuth API/api/auth/[...nextauth]前端页面(app/)用户(浏览器)1️⃣ 用户提交登录表单2️⃣ NextAuth 验证用户3️⃣ 生成 Session Cookie4️⃣ 用户访问受保护接口5️⃣ 前端通过 getServerSession 或 useSession随时获取当前用户输入 Email PasswordPOST /api/auth/callback/credentials{ email, password }SELECT * FROM users WHERE email?返回 user passwordHashbcrypt.compare(password, passwordHash)登录成功 { user }写入加密的 next-auth.session-token设置浏览器 CookieGET /api/protected附带 Cookie验证 Cookie 有效性Session { user }返回受保护数据✅ 关键点说明Session Token 存在 CookieCookie 名next-auth.session-token或 __Secure-next-auth.session-token默认有效期30 天Session 校验方式每次请求时NextAuth 从 Cookie 解密出 token确认 session 是否有效。如果用 getServerSession(authOptions) → 直接在服务端验证。保护 API/页面API 路由在 route.ts 里用 getServerSession 检查用户是否已登录。页面在 page.tsx 里用 redirect(“/auth/signin”) 把未登录用户踢回登录页。 感谢阅读想了解更多 我的博客网站 | 记录思考分享干货 我的个人主页 | 关于我、开源项目