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

SvelteKit结合Laravel Sanctum实现用户认证及路由保护的方案咨询

SvelteKit + Laravel Sanctum 认证最优实现方案

现有代码核心问题

  • 调用Laravel接口时未携带credentials参数,无法获取并保存Sanctum下发的CSRF cookie与会话cookie
  • 自定义user cookie存储登录态,未和Laravel会话同步,存在安全性问题和状态不一致风险
  • 未实现路由保护逻辑,敏感路由未校验登录态
  • 未转发Laravel返回的set-cookie头到客户端,会话无法持久化

修正后实现步骤

1. 前置后端配置

Laravel项目的.env需要做以下配置:

SANCTUM_STATEFUL_DOMAINS=localhost:3000 # 替换为你的SvelteKit访问地址
SESSION_DOMAIN=localhost # 本地测试用,线上换你的根域名
SESSION_DRIVER=cookie

同时确保Laravel的cors.php配置中supports_credentials设为true,允许的路径包含sanctum/csrf-cookie、api/*等接口。

2. 修正登录页面代码

// src/routes/login/+page.svelte
<script>
let email;
let password;
let error = '';

async function login() {
    error = '';
    const res = await fetch('/login', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json'
        },
        body: JSON.stringify({ email, password })
    });
    if (res.ok) {
        // 登录成功跳转到首页或者仪表盘
        window.location.href = '/dashboard';
    } else {
        error = '邮箱或密码错误';
    }
}
</script>

<h1>Login Page</h1>
{#if error}
<p style="color: red">{error}</p>
{/if}
<form on:submit|preventDefault={login}>
    <input bind:value={email} type="email" name="email" placeholder="邮箱" required />
    <input bind:value={password} type="password" name="password" placeholder="密码" required />
    <button type="submit">提交</button>
</form>

3. 修正登录服务端端点

// src/routes/login/+server.js
export async function POST({ request, cookies }) {
    // 先获取CSRF cookie
    await fetch('http://localhost:8000/sanctum/csrf-cookie', {
        credentials: 'include'
    });

    // 调用登录接口
    const loginRes = await fetch('http://localhost:8000/api/login', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
            accept: 'application/json',
            // 转发客户端的cookie到Laravel
            cookie: request.headers.get('cookie') || ''
        },
        credentials: 'include',
        body: JSON.stringify(await request.json())
    });

    // 转发Laravel返回的set-cookie到客户端
    const setCookie = loginRes.headers.get('set-cookie');
    const user = await loginRes.json();

    return new Response(JSON.stringify(user), {
        status: loginRes.status,
        headers: {
            'Content-Type': 'application/json',
            ...(setCookie && { 'set-cookie': setCookie })
        }
    });
}

4. 修正hooks逻辑,同步登录态

// src/hooks.server.js
import { redirect } from '@sveltejs/kit';
import cookie from 'cookie';

export async function handle({ event, resolve }) {
    const cookies = cookie.parse(event.request.headers.get('cookie') || '');
    // 每次请求都去Laravel校验登录态,保证和后端会话同步
    try {
        const userRes = await fetch('http://localhost:8000/api/user', {
            headers: {
                accept: 'application/json',
                cookie: event.request.headers.get('cookie') || ''
            },
            credentials: 'include'
        });
        if (userRes.ok) {
            event.locals.user = await userRes.json();
        } else {
            event.locals.user = null;
        }
    } catch (e) {
        event.locals.user = null;
    }

    // 路由保护:访问/dashboard开头的路径需要登录
    if (event.url.pathname.startsWith('/dashboard') && !event.locals.user) {
        throw redirect(302, '/login');
    }

    const response = await resolve(event);
    return response;
}

export async function getSession(event) {
    return {
        user: event.locals.user
    };
}

5. 全局布局代码调整

// src/routes/+layout.svelte
<script context="module">
    export async function load({ session }) {
        return {
            props: {
                user: session.user
            }
        };
    }
</script>

<script>
    export let user;
</script>

<nav class="nav">
    <ul>
        <li><a href="/">首页</a></li>
        {#if !user}
        <li><a href="/login">登录</a></li>
        {:else}
        <li><a href="/dashboard">仪表盘</a></li>
        <li><a href="/logout">登出</a></li>
        {/if}
    </ul>
    {#if user}
    <div>当前用户:{user.email}</div>
    {/if}
</nav>

<slot />

补充说明

如果需要调用其他Laravel接口,统一走SvelteKit的服务端端点转发,每次请求都带上客户端的cookie和credentials: 'include'即可,不需要额外处理认证逻辑。登出逻辑同理,调用Laravel的登出接口后清空会话即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 09:36:04