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

NodeJS+ExpressJS+SQLite3用户登出功能问题求助

问题解决方案

一、前端按钮状态切换实现

当前仅用CSS隐藏登出按钮,需通过JavaScript根据登录状态动态切换按钮显示逻辑:

  1. 页面加载时自动检查本地Token,初始化按钮显示状态
  2. 登录成功后立即切换按钮状态
  3. 登出时清除Token并恢复初始状态

修改signInScript.js如下:

document.addEventListener('DOMContentLoaded', function() {
    const emailInput = document.getElementById('signInEmailAddress');
    const passwordInput = document.getElementById('signInPassword');
    const submitButton = document.getElementById('submitButton');
    const togglePasswordIcon = document.getElementById('togglePassword');
    // 替换为你实际的登录/登出按钮ID
    const loginButton = document.getElementById('loginButton');
    const logoutButton = document.getElementById('logoutButton');

    // 初始化按钮显示状态
    function setButtonVisibility() {
        const token = localStorage.getItem('token');
        if (token) {
            loginButton.style.display = 'none';
            logoutButton.style.display = 'block';
        } else {
            loginButton.style.display = 'block';
            logoutButton.style.display = 'none';
        }
    }

    // 页面加载时执行初始化
    setButtonVisibility();

    // 绑定登出按钮事件
    logoutButton.addEventListener('click', function() {
        localStorage.removeItem('token');
        setButtonVisibility();
        // 可选:跳转到首页或登录页面
        window.location.href = '/';
    });

    // 原表单验证逻辑
    function checkFormValidity() {
        const isValid = emailInput.value.trim() !== '' && passwordInput.value.trim() !== '';
        submitButton.disabled = !isValid;
    }

    // 原密码显示切换逻辑
    function togglePasswordVisibility() {
        const type = passwordInput.type === 'password' ? 'text' : 'password';
        passwordInput.type = type;
        togglePasswordIcon.classList.toggle('fa-eye-slash');
    }

    // 原输入事件监听
    emailInput.addEventListener('input', checkFormValidity);
    passwordInput.addEventListener('input', checkFormValidity);
    togglePasswordIcon.addEventListener('click', togglePasswordVisibility);

    // 原表单提交逻辑
    document.getElementById("signInForm").addEventListener("submit", function(event) {
        event.preventDefault();
    
        const email = document.getElementById("signInEmailAddress").value;
        const password = document.getElementById("signInPassword").value;
    
        const data = {
            email: email,
            password: password
        };
    
        fetch('/login', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json'
            },
            body: JSON.stringify(data)
        })
        .then(response => {
            if (response.ok) {
                return response.json();
            } else {
                console.error('Login failed');
                alert("Login Failed!");
                throw new Error('Login failed');
            }
        })
        .then(data => {
            console.log('User data:', data.user);
            alert("Login Successful!");
            localStorage.setItem('token', data.token);
            // 登录成功后切换按钮状态
            setButtonVisibility();
        })
        .catch(error => {
            console.error('Error:', error);
        });
    });
});

二、服务器端登出功能修正

当前/logout接口依赖express-session,但你使用的是JWT无状态认证,req.logout()和req.session.destroy()完全无效,且你未正确配置session中间件,会导致运行报错。

JWT的登出核心逻辑是前端清除本地存储的Token,服务器端无需额外操作(若需强制Token失效,可维护Token黑名单,简单场景下可省略)。修改server.js中的登出接口:

// 移除未使用的session和cookie-parser依赖(你原本也没配置)
// const cookieParser = require('cookie-parser');
// const session = require('express-session');

// 修改登出接口
app.get('/logout', (req, res) => {
    // JWT无状态,仅返回成功响应即可
    res.status(200).json({ message: 'Logout successful' });
});

三、Token与用户关联验证

1. 前端验证Token内容

登录成功后可解析Token,确认用户信息是否正确:

// 在登录成功的then回调中添加
const decodedToken = jwt.decode(data.token);
console.log('解析后的Token:', decodedToken); // 应包含userId和email字段

注:前端需引入jsonwebtoken包,或使用在线JWT解析工具验证。

2. 服务器端添加Token验证中间件

创建中间件验证请求中的Token,确保请求来自已登录用户:

// 在server.js中添加JWT验证中间件
function authenticateToken(req, res, next) {
    // 从请求头获取Token(前端需携带Authorization: Bearer <token>)
    const authHeader = req.headers['authorization'];
    const token = authHeader && authHeader.split(' ')[1];

    if (!token) {
        return res.status(401).json({ error: '需要登录凭证' });
    }

    jwt.verify(token, 'your-secret-key', (err, user) => {
        if (err) {
            return res.status(403).json({ error: 'Token无效或已过期' });
        }
        req.user = user; // 将用户信息挂载到req对象,后续接口可直接使用
        next();
    });
}

// 示例:用中间件保护需要登录的接口
app.get('/user/profile', authenticateToken, (req, res) => {
    res.json({ message: '用户个人信息', user: req.user });
});

3. 前端请求时携带Token

在需要登录权限的请求中,将Token放在请求头:

fetch('/user/profile', {
    method: 'GET',
    headers: {
        'Authorization': `Bearer ${localStorage.getItem('token')}`
    }
})
.then(response => response.json())
.then(data => console.log(data));

额外优化建议

  • 删除server.js中的GET方式/login接口,该方式会将密码暴露在URL中,存在安全风险
  • 生产环境中禁止明文存储密码,需使用bcrypt等工具对密码进行哈希处理

内容的提问来源于stack exchange,提问作者Aadil Hafesji

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 00:19:52