You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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重定向到/时,浏览器请求/并未携带刚设置的email Cookie,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;

验证修复效果

修改后重新测试:

  1. 登录成功后重定向到回调页,验证Cookie是否正确设置
  2. 重定向到首页时,检查hooks.server.js是否能读取到email Cookie
  3. 确认不再出现循环重定向

内容的提问来源于stack exchange,提问作者ImSoHappy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 14:37:33