SvelteKit结合Laravel Sanctum实现用户认证及路由保护的方案咨询
SvelteKit + Laravel Sanctum 认证最优实现方案
现有代码核心问题
- 调用Laravel接口时未携带
credentials参数,无法获取并保存Sanctum下发的CSRF cookie与会话cookie - 自定义
usercookie存储登录态,未和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
相关产品推荐
相关产品推荐

