Svelte+Express未登录路由拦截与重定向实现咨询
实现Svelte+Express项目的登录状态控制与页面重定向
需求概述
- 未登录用户访问任何受保护页面时,自动重定向至
/login - 登录成功后可访问
/home及其他页面 - 通过Cookie持久化登录状态
现有代码
Login.svelte
<script> import { goto } from '$app/navigation'; import { onMount } from 'svelte'; let email = ''; let password = ''; async function handleLogin() { const response = await fetch('http://localhost:3000/api/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email, password }) }); const data = await response.json(); if (data.isLogged) { console.log('User logged in'); goto('/home'); } else { console.log('Login failed:', data.message); } } </script>
Express server.js 登录接口
app.post("/api/login", function (req, res) { const { email, password } = req.body; con.query( `SELECT * FROM Utenti WHERE email = '${email}'`, function (err, result) { if (err) { res.send({ isLogged: false, message: err }); } else { if (result.length === 0) { res.send({ isLogged: false, message: "No user found" }); } else { const user = result[0]; bcrypt.compare( password, user.password, function (err, result) { if (result) { res.send({ isLogged: true, message: "Login successful", }); } else { res.send({ isLogged: false, message: "Incorrect password", }); } } ); } } } ); });
当前SvelteKit +page.server.ts
import { redirect } from "@sveltejs/kit"; export function load() { throw redirect(307, "/home"); }
解决方案
1. Express端:登录成功后设置HttpOnly Cookie
先修复SQL注入风险(改用参数化查询),再在登录成功时设置安全Cookie存储用户标识:
app.post("/api/login", function (req, res) { const { email, password } = req.body; // 参数化查询避免SQL注入 con.query( 'SELECT * FROM Utenti WHERE email = ?', [email], function (err, result) { if (err) { return res.send({ isLogged: false, message: err.message }); } if (result.length === 0) { return res.send({ isLogged: false, message: "No user found" }); } const user = result[0]; bcrypt.compare(password, user.password, function (err, isMatch) { if (err) { return res.send({ isLogged: false, message: err.message }); } if (isMatch) { // 设置HttpOnly Cookie,防范XSS攻击 res.cookie('userId', user.id, { httpOnly: true, secure: process.env.NODE_ENV === 'production', // 生产环境启用HTTPS sameSite: 'strict', maxAge: 24 * 60 * 60 * 1000, // 有效期1天 path: '/' }); return res.send({ isLogged: true, message: "Login successful", user: { id: user.id, email: user.email } }); } else { return res.send({ isLogged: false, message: "Incorrect password", }); } }); } ); });
2. Express端:添加登录状态验证接口(可选)
用于SvelteKit服务端校验Cookie有效性:
app.get("/api/verify-login", function (req, res) { const userId = req.cookies.userId; if (!userId) { return res.send({ isValid: false }); } con.query('SELECT id, email FROM Utenti WHERE id = ?', [userId], function (err, result) { if (err || result.length === 0) { res.clearCookie('userId', { path: '/' }); return res.send({ isValid: false }); } return res.send({ isValid: true, user: result[0] }); }); });
3. SvelteKit端:全局页面保护(+layout.server.ts)
在根目录创建+layout.server.ts,实现全局登录校验:
import { redirect } from '@sveltejs/kit'; export async function load({ cookies, fetch }) { const userId = cookies.get('userId'); // 无Cookie直接重定向到登录页 if (!userId) { throw redirect(303, '/login'); } // 验证Cookie有效性(增强安全性) const verifyRes = await fetch('http://localhost:3000/api/verify-login', { headers: { Cookie: `userId=${userId}` } }); const verifyData = await verifyRes.json(); if (!verifyData.isValid) { cookies.delete('userId', { path: '/' }); throw redirect(303, '/login'); } // 返回用户信息给页面组件使用 return { user: verifyData.user }; }
4. SvelteKit端:登录页特殊处理(+page.server.ts)
修改登录页的+page.server.ts,避免已登录用户重复访问:
import { redirect } from '@sveltejs/kit'; export async function load({ cookies }) { // 如果已登录,直接重定向到首页 if (cookies.get('userId')) { throw redirect(303, '/home'); } }
5. 退出登录功能(可选)
Express端接口
app.post("/api/logout", function (req, res) { res.clearCookie('userId', { path: '/' }); res.send({ success: true, message: "Logged out successfully" }); });
Svelte端调用示例
在需要退出的组件中添加:
<script> import { goto } from '$app/navigation'; import { invalidateAll } from '$app/navigation'; async function handleLogout() { await fetch('http://localhost:3000/api/logout', { method: 'POST' }); invalidateAll(); // 清除页面缓存 goto('/login'); } </script> <button on:click={handleLogout}>退出登录</button>
内容的提问来源于stack exchange,提问作者Skerdi Velo
相关产品推荐
相关产品推荐

