SvelteKit中hooks.server与page.server认证无限循环问题排查
SvelteKit认证流程无限循环问题修复
问题描述
主页面与登录系统分属不同域名,用户登录成功后会携带token重定向到/auth/callback;该页面的+page.server.js验证token通过后,设置会话cookie并重定向到首页/。但实际流程中,登录成功进入回调页后,会陷入登录页与回调页的反复重定向循环,直接访问首页则无此问题。
日志显示+page.server.js执行两次,hooks.server.js仅执行一次,且cookie已正确设置但循环无法停止。
执行日志
cookie saved redirecting to login cookie saved cookie saved redirecting to login cookie saved cookie saved redirecting to login
相关代码
hooks.server.js
import { LOGIN_URL } from '$env/static/private'; import { redirect } from '@sveltejs/kit'; import cookie from 'cookie'; export const handle = async ({ event, resolve }) => { const requestedPath = event.url.pathname; const host = event.url.host; const publicPaths = ['/auth/callback', '/auth/logout']; if (publicPaths.includes(requestedPath)) { return resolve(event); } const cookies = cookie.parse(event.request.headers.get('cookie') || ''); const email = cookies.email; if (!email) { console.log("redirecting to login"); throw redirect(303, `${LOGIN_URL}?srv=${host}/auth/callback`); } return await resolve(event); };
/auth/callback/+page.server.js
import { validateToken } from '../../../lib/auth'; import { redirect } from '@sveltejs/kit'; import { LOGIN_URL } from '$env/static/private'; export const load = async ({ url, cookies }) => { const token = url.searchParams.get('apiToken'); if (token) { const { success, data, error } = await validateToken(token); if (!success) { throw redirect(303, `${LOGIN_URL}/error?type=AuthError`); } const email = data.data.email; cookies.set('email', email, { httpOnly: true, secure: false, sameSite: 'strict', maxAge: 86400 * 1, path: '/' }); console.log("cookie saved"); throw redirect(303, '/'); } else { throw redirect(303, `${LOGIN_URL}/error?type=AuthError`); } };
问题原因分析
核心问题出在Cookie的SameSite属性设置:
- 登录系统与主站属于不同域名,跨域重定向到
/auth/callback后,设置了sameSite: 'strict'的Cookie,浏览器会拒绝在后续跨域发起的请求中携带该Cookie。 - 当
/auth/callback重定向到/时,浏览器请求/并未携带刚设置的emailCookie,hooks.server.js检测不到Cookie,便重定向回登录页,触发循环。 - 日志中多次出现
cookie saved是因为每次循环都会重新进入回调页执行token验证和Cookie设置。
解决方案
1. 调整SameSite属性
将Cookie的sameSite从strict改为lax,允许跨域重定向时携带Cookie:
cookies.set('email', email, { httpOnly: true, secure: false, // 开发环境用false,生产HTTPS环境改为true sameSite: 'lax', // 替换strict为lax maxAge: 86400 * 1, path: '/' });
如果需要在跨域AJAX请求中也携带Cookie,可以设置sameSite: 'none',但必须同时开启secure: true(仅HTTPS环境可用):
cookies.set('email', email, { httpOnly: true, secure: true, // 必须为true sameSite: 'none', maxAge: 86400 * 1, path: '/' });
2. 验证路径匹配(可选)
确保hooks.server.js中的publicPaths能正确匹配回调路径,避免因路径带斜杠等问题导致误拦截:
// 将精确匹配改为前缀匹配,兼容带斜杠的情况 if (publicPaths.some(path => requestedPath.startsWith(path))) { return resolve(event); }
3. 确认Cookie生效逻辑
可以在hooks.server.js中添加日志,检查请求头中的Cookie是否被正确携带:
const cookies = cookie.parse(event.request.headers.get('cookie') || ''); console.log('Received cookies:', cookies); // 新增日志 const email = cookies.email;
验证修复效果
修改后重新测试:
- 登录成功后重定向到回调页,验证Cookie是否正确设置
- 重定向到首页时,检查
hooks.server.js是否能读取到emailCookie - 确认不再出现循环重定向
内容的提问来源于stack exchange,提问作者ImSoHappy
相关产品推荐
相关产品推荐

