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

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");
}

解决方案

先修复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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 08:35:03