如何在Next.js中结合AuthContext与Middleware使用Cookie?
核心思路
把Cookie设置逻辑完全放到服务端(Server Action),客户端组件只负责触发登录请求、同步AuthContext状态,彻底避免在客户端组件里调用服务端专属API(比如next/headers)。
具体实现步骤
1. 编写Server Action处理登录与Cookie设置
在服务端专属文件(比如app/actions/auth.actions.ts)里实现登录逻辑,这里可以安全使用next/headers操作Cookie:
'use server'; import { cookies } from 'next/headers'; import { redirect } from 'next/navigation'; export async function login(formData: FormData) { // 从表单提取账号密码 const email = formData.get('email') as string; const password = formData.get('password') as string; // 调用身份提供商的验证接口 const authResponse = await fetch('https://你的身份验证地址/login', { method: 'POST', body: JSON.stringify({ email, password }), headers: { 'Content-Type': 'application/json' }, }); if (!authResponse.ok) { throw new Error('登录失败,请检查账号密码'); } const { accessToken, userInfo } = await authResponse.json(); // 设置HttpOnly Cookie(防止XSS攻击,提升安全性) cookies().set('accessToken', accessToken, { httpOnly: true, secure: process.env.NODE_ENV === 'production', maxAge: 60 * 60 * 24, // 有效期1天 path: '/', }); // 登录成功后重定向到目标页面 redirect('/'); } // 登出逻辑:清除Cookie export async function logout() { cookies().delete('accessToken'); redirect('/login'); }
2. 改造AuthContext客户端组件
AuthContext只负责管理客户端用户状态,不再处理Cookie操作,通过调用Server Action完成登录/登出,同步状态:
'use client'; import { createContext, useContext, useState, useEffect } from 'react'; import { login as serverLogin, logout as serverLogout } from '@/app/actions/auth.actions'; type AuthContextType = { user: any | null; login: (formData: FormData) => Promise<void>; logout: () => Promise<void>; }; const AuthContext = createContext<AuthContextType | undefined>(undefined); export function AuthProvider({ children }: { children: React.ReactNode }) { const [user, setUser] = useState<any | null>(null); // 调用服务端登录Action const login = async (formData: FormData) => { try { await serverLogin(formData); // 登录成功后拉取用户信息同步到Context const res = await fetch('/api/user'); if (res.ok) setUser(await res.json()); } catch (err) { console.error(err); } }; // 调用服务端登出Action const logout = async () => { await serverLogout(); setUser(null); }; // 组件挂载时同步当前用户状态 useEffect(() => { const fetchUser = async () => { const res = await fetch('/api/user'); if (res.ok) setUser(await res.json()); }; fetchUser(); }, []); return ( <AuthContext.Provider value={{ user, login, logout }}> {children} </AuthContext.Provider> ); } export const useAuth = () => { const context = useContext(AuthContext); if (!context) throw new Error('useAuth必须在AuthProvider内部使用'); return context; };
3. 登录表单组件调用逻辑
在客户端表单里直接调用AuthContext的登录方法即可:
'use client'; import { useAuth } from '@/app/context/AuthContext'; export default function LoginForm() { const { login } = useAuth(); return ( <form action={login}> <input type="email" name="email" placeholder="邮箱" required /> <input type="password" name="password" placeholder="密码" required /> <button type="submit">登录</button> </form> ); }
4. Middleware验证Cookie
在middleware.ts里读取Cookie并验证token有效性:
import { NextResponse } from 'next/server'; import type { NextRequest } from 'next/server'; export async function middleware(request: NextRequest) { const accessToken = request.cookies.get('accessToken')?.value; // 无需验证的公开路由 const publicPaths = ['/login', '/signup', '/_next', '/favicon.ico']; const isPublic = publicPaths.some(path => request.nextUrl.pathname.startsWith(path)); if (isPublic) return NextResponse.next(); // 无token则重定向到登录页 if (!accessToken) { return NextResponse.redirect(new URL('/login', request.url)); } // 调用身份提供商验证token有效性 const validateRes = await fetch('https://你的身份验证地址/validate-token', { method: 'POST', body: JSON.stringify({ accessToken }), headers: { 'Content-Type': 'application/json' }, }); // token无效则清除Cookie并重定向 if (!validateRes.ok) { const response = NextResponse.redirect(new URL('/login', request.url)); response.cookies.delete('accessToken'); return response; } // 验证通过,允许访问 return NextResponse.next(); } // 指定生效的路由范围 export const config = { matcher: ['/((?!api|_next/static|_next/image|favicon.ico).*)'], };
关键注意事项
- HttpOnly Cookie:必须开启
httpOnly: true,禁止前端JS读取Cookie,避免XSS攻击风险。 - 服务端状态同步:客户端用户状态通过调用服务端接口(比如
/api/user)获取,不要直接从Cookie读取敏感信息。 - Server Action安全性:Server Action默认运行在服务端,无需额外配置CORS,不用担心跨域问题。
内容的提问来源于stack exchange,提问作者a11smiles
相关产品推荐
相关产品推荐

