Next.js(App Router)对接Express-Session外部API的鉴权与路由保护问题
Next.js App Router 对接Express Session API 实现登录与路由保护
1. 登录流程实现
前端登录组件(客户端组件)
创建客户端组件处理登录表单,调用Express登录接口时必须开启credentials: 'include',确保浏览器能保存返回的Session Cookie:
'use client'; import { useState } from 'react'; export default function LoginForm() { const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); try { const res = await fetch('http://your-express-api.com/api/login', { method: 'POST', headers: { 'Content-Type': 'application/json', }, credentials: 'include', // 关键:允许携带Cookie body: JSON.stringify({ email, password }), }); if (res.ok) { // 登录成功,跳转到受保护页面 window.location.href = '/dashboard'; } else { const error = await res.json(); alert(error.message || '登录失败'); } } catch (err) { alert('网络错误,请重试'); } }; return ( <form onSubmit={handleSubmit}> <input type="email" value={email} onChange={(e) => setEmail(e.target.value)} placeholder="邮箱" required /> <input type="password" value={password} onChange={(e) => setPassword(e.target.value)} placeholder="密码" required /> <button type="submit">登录</button> </form> ); }
Express端关键配置
确保Express的CORS和Session配置允许跨域Cookie传递:
const express = require('express'); const session = require('express-session'); const cors = require('cors'); const app = express(); // CORS配置:允许Next.js域名,允许携带凭证 app.use(cors({ origin: 'http://your-nextjs-app.com', // 替换成你的Next.js域名 credentials: true, })); // Session配置:注意Cookie的跨域参数 app.use(session({ secret: 'your-secret-key', resave: false, saveUninitialized: false, cookie: { secure: process.env.NODE_ENV === 'production', // 生产环境开启HTTPS sameSite: process.env.NODE_ENV === 'production' ? 'none' : 'lax', // 跨域时设为none maxAge: 24 * 60 * 60 * 1000, // 1天有效期 }, })); // 登录接口示例 app.post('/api/login', (req, res) => { const { email, password } = req.body; // 这里替换成你的用户验证逻辑 if (email === 'user@example.com' && password === 'password') { req.session.user = { id: 1, email }; // 将用户信息存入session res.json({ message: '登录成功' }); } else { res.status(401).json({ message: '账号或密码错误' }); } }); // 验证用户状态的接口(供Next.js调用) app.get('/api/me', (req, res) => { if (req.session.user) { res.json(req.session.user); } else { res.status(401).json({ message: '未登录' }); } });
2. 用户状态验证工具
创建一个服务端工具函数,用于在服务端验证用户Session状态:
// app/lib/auth.ts export async function getCurrentUser() { try { const res = await fetch('http://your-express-api.com/api/me', { credentials: 'include', // 携带Session Cookie }); if (res.ok) { return await res.json(); } return null; } catch (err) { return null; } }
3. 路由保护实现
方式一:使用Middleware全局拦截(推荐)
在项目根目录创建middleware.ts,全局拦截受保护路由,验证用户状态:
// middleware.ts import { NextResponse } from 'next/server'; import type { NextRequest } from 'next/server'; export async function middleware(request: NextRequest) { // 定义需要保护的路由前缀 const protectedRoutes = ['/dashboard', '/profile']; const isProtectedRoute = protectedRoutes.some(route => request.nextUrl.pathname.startsWith(route)); if (!isProtectedRoute) { return NextResponse.next(); } // 调用Express的验证接口 const res = await fetch('http://your-express-api.com/api/me', { headers: { Cookie: request.headers.get('Cookie') || '', // 传递请求中的Cookie }, }); if (!res.ok) { // 未登录,重定向到登录页 return NextResponse.redirect(new URL('/login', request.url)); } return NextResponse.next(); } // 指定Middleware生效的路由 export const config = { matcher: ['/dashboard/:path*', '/profile/:path*'], };
方式二:在服务端页面组件中验证
对于单个受保护页面,可以直接在服务端组件中调用验证函数,未登录则重定向:
// app/dashboard/page.tsx import { redirect } from 'next/navigation'; import { getCurrentUser } from '../lib/auth'; export default async function DashboardPage() { const user = await getCurrentUser(); if (!user) { redirect('/login'); } return ( <div> <h1>欢迎,{user.email}</h1> <p>这是你的仪表盘</p> </div> ); }
公共路由
所有未被Middleware或页面组件拦截的路由(如/、/login、/about)默认作为公共路由,无需验证即可访问。
内容的提问来源于stack exchange,提问作者Ertan Özdemir
相关产品推荐
相关产品推荐

