Next.js 14(App Router)自定义.NET后端认证两大问题求助
解决方案建议
问题一:令牌刷新后Local Storage的Access Token同步问题
方案1:刷新时主动更新Local Storage
在调用刷新令牌的API逻辑里,拿到新的Access Token后直接执行Local Storage更新操作。比如:
const refreshToken = async () => { const response = await fetch('/api/refresh-token', { method: 'POST', credentials: 'include' // 携带Cookie中的Refresh Token }); const data = await response.json(); if (data.accessToken) { localStorage.setItem('accessToken', data.accessToken); } };
如果你的刷新逻辑封装在Axios拦截器这类全局请求处理中,就在响应拦截部分,检测到401并成功刷新令牌后,同步更新Local Storage。
方案2:移除Local Storage存储,改用HttpOnly Cookie(推荐)
Local Storage存Access Token存在XSS攻击风险,更安全的做法是把Access Token也存入HttpOnly Cookie。后端刷新令牌后会自动更新Cookie,前端无需处理同步问题,API请求时浏览器会自动携带Cookie,后端直接验证即可。
修改认证成功后的逻辑:仅将Access Token、Refresh Token、用户信息存入HttpOnly Cookie,不再写入Local Storage。前端发起API请求时,确保请求带上credentials: 'include'(或same-origin,根据跨域配置调整)。
问题二:路由保护中间件的严谨性优化
当前仅检查Cookie存在远远不够,需要验证Token的有效性,具体实现步骤如下:
- 安装JWT验证库(若使用JWT令牌)
安装支持Edge Runtime的jose库:
npm install jose
- 编写Middleware逻辑
在项目根目录的middleware.ts中实现Token验证:
import { NextResponse } from 'next/server'; import type { NextRequest } from 'next/server'; import { jwtVerify } from 'jose'; export async function middleware(request: NextRequest) { // 从Cookie获取Access Token const accessToken = request.cookies.get('accessToken')?.value; const protectedPaths = ['/dashboard', '/profile']; // 你的受保护路由列表 // 访问受保护路由但无Token,重定向至登录页 if (protectedPaths.some(path => request.nextUrl.pathname.startsWith(path)) && !accessToken) { return NextResponse.redirect(new URL('/login', request.url)); } if (accessToken) { try { // 验证JWT签名与过期时间,替换为你的后端公钥 const secret = new TextEncoder().encode(process.env.JWT_SECRET!); await jwtVerify(accessToken, secret); // 验证通过,放行请求 return NextResponse.next(); } catch (error) { // Token无效,尝试刷新 const refreshToken = request.cookies.get('refreshToken')?.value; if (!refreshToken) { // 无Refresh Token,重定向登录 return NextResponse.redirect(new URL('/login', request.url)); } // 调用后端刷新接口 const refreshResponse = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/refresh`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ refreshToken }), credentials: 'include' }); if (refreshResponse.ok) { const data = await refreshResponse.json(); // 更新Cookie中的Access Token const response = NextResponse.next(); response.cookies.set('accessToken', data.accessToken, { httpOnly: true, secure: process.env.NODE_ENV === 'production', sameSite: 'strict', maxAge: 3600 // 与后端保持一致的有效期 }); return response; } else { // 刷新失败,重定向登录 return NextResponse.redirect(new URL('/login', request.url)); } } } } // 指定需要经过Middleware的路由 export const config = { matcher: ['/dashboard/:path*', '/profile/:path*'] };
注意事项
- 确保后端JWT公钥/密钥正确配置在环境变量中
- 刷新令牌接口需验证Refresh Token有效性,并返回新的Access Token
- Middleware运行在Edge Runtime,避免使用Node.js专属API
内容的提问来源于stack exchange,提问作者Zakaria
相关产品推荐
相关产品推荐

