如何在SvelteKit中安全存储JWT并实现登录态持久化?
符合SvelteKit规范的JWT安全存储与持久化登录实现方案
核心原则:敏感的JWT凭证绝对不要存储在客户端localStorage或者JS可读写的普通cookie中,通过SvelteKit服务端设置带HttpOnly、Secure、SameSite安全属性的cookie是官方推荐的最安全方案,同时天然支持用户重启浏览器后保持登录状态。
第一步:新增服务端登录API路由
将原来客户端直接调用后端登录接口的逻辑移到SvelteKit服务端处理,由服务端负责接收token并设置cookie。
新建文件src/routes/api/login/+server.js,代码如下:
import { json } from '@sveltejs/kit'; export async function POST({ request, cookies }) { const { username, password } = await request.json(); // 调用你的后端登录接口获取token,替换为实际的后端接口地址 const backendResponse = await fetch('后端登录接口地址', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ username, password }) }); const result = await backendResponse.json(); if (backendResponse.ok && result.token?.access_token) { // 服务端设置安全cookie,属性配置可以根据需求调整 cookies.set('access_token', result.token.access_token, { path: '/', httpOnly: true, // 禁止客户端JS读取,彻底避免XSS攻击窃取token secure: process.env.NODE_ENV === 'production', // 生产环境仅在HTTPS下传输 sameSite: 'strict', // 避免CSRF攻击 maxAge: 60 * 60 * 24 * 7 // cookie有效期7天,对应保持登录的时长 }); return json({ success: true }); } else { return json({ success: false, message: result.message || '登录失败' }, { status: 400 }); } }
第二步:修改客户端登录页的提交逻辑
把原来直接调用后端接口的逻辑替换为调用自己的服务端API路由,调整submit函数:
async function submit(event) { errors = null; try { const res = await fetch('/api/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ username, password }) }); const data = await res.json(); if (res.ok) { goto('/profile'); } else { message = data.message; hasError = true; setTimeout(() => { hasError = false }, 5000); } } catch (e) { message = '网络异常,请稍后重试'; hasError = true; setTimeout(() => { hasError = false }, 5000); } }
第三步:实现持久化登录状态校验
通过SvelteKit的服务端钩子统一读取cookie,初始化登录状态,新建文件src/hooks.server.js:
export async function handle({ event, resolve }) { const accessToken = event.cookies.get('access_token'); if (accessToken) { // 可在此处添加token有效性校验逻辑:比如请求后端验签、或者本地解析JWT获取用户信息 event.locals.user = { isLoggedIn: true /* 可补充解析后的用户ID、用户名等信息 */ }; } else { event.locals.user = null; } return resolve(event); }
调整你原有页面的load函数,直接从服务端上下文读取登录状态即可:
export async function load({ locals }) { if (locals.user) { return { status: 302, redirect: '/' }; } return {}; }
第四步:接口请求带token的处理
所有需要携带JWT请求后端的场景,都统一走SvelteKit服务端API路由转发,由服务端从cookie读取token添加到请求头,避免token暴露到客户端:
示例:获取用户信息的服务端API路由src/routes/api/profile/+server.js
import { json } from '@sveltejs/kit'; export async function GET({ cookies }) { const accessToken = cookies.get('access_token'); if (!accessToken) return json({ error: '未登录' }, { status: 401 }); // 调用后端接口,携带token const backendRes = await fetch('后端用户信息接口地址', { headers: { 'Authorization': `Bearer ${accessToken}` } }); return json(await backendRes.json()); }
补充:退出登录实现
只需新增一个服务端API路由,删除对应cookie即可:
// src/routes/api/logout/+server.js import { json } from '@sveltejs/kit'; export async function POST({ cookies }) { cookies.delete('access_token', { path: '/' }); return json({ success: true }); }
内容的提问来源于stack exchange,提问作者Kodoxa
相关产品推荐
相关产品推荐

