Express + MongoDB 实现用户登出

一、简单登出(客户端移除 JWT)

这种方式只需要客户端移除本地存储的 JWT 即可,服务端不需要额外处理。

javascript 复制代码
<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <meta name="viewport" content="width=device-width, initial-scale=1.0" />

    <title>User Logout</title>

  </head>



  <body>

    <button id="logoutButton">Logout</button>

    <script>

      const logoutButton = document.getElementById("logoutButton");

      logoutButton.addEventListener("click", () => {

        // 移除本地存储的 JWT

        localStorage.removeItem("jwtToken");

        // 可以跳转到登录页面

        window.location.href = "/login";

      });

    </script>

  </body>

</html>

二、服务端辅助登出(JWT 黑名单)

为了防止已登出的 JWT 被恶意使用,服务端可以将登出的 JWT 加入黑名单。可以使用 MongoDB 来存储这个黑名单。

1. 创建黑名单模型(`blacklistModel.js`)

javascript 复制代码
const mongoose = require("mongoose");

const blacklistSchema = new mongoose.Schema({

  token: {

    type: String,

    required: true,

    unique: true,

  },

  expiresAt: {

    type: Date,

    default: Date.now,

    expires: "1h", // 设置自动过期时间,与 JWT 过期时间一致

  },

});

const Blacklist = mongoose.model("Blacklist", blacklistSchema);

module.exports = Blacklist;

2. 在 `app.js` 中添加登出路由

javascript 复制代码
const express = require("express");

const connectDB = require("./db");

const User = require("./userModel");

const jwt = require("jsonwebtoken");

const Blacklist = require("./blacklistModel");

const app = express();

const port = 3000;

const secretKey = "yourSecretKey";

// 解析请求体中的 JSON 数据

app.use(express.json());

// 连接数据库

connectDB();

// 处理用户登出的路由

app.post("/logout", async (req, res) => {

  try {

    const token = req.headers["authorization"]?.split(" ")[1];

    if (!token) {

      return res.status(401).json({ message: "No token provided" });

    }

    // 验证 JWT

    jwt.verify(token, secretKey, async (err, decoded) => {

      if (err) {

        return res.status(401).json({ message: "Invalid token" });

      }

      // 将 JWT 加入黑名单

      const newBlacklistedToken = new Blacklist({ token });

      await newBlacklistedToken.save();

      res.json({ message: "Logout successful" });

    });

  } catch (error) {

    console.error("Error during logout:", error);

    res.status(500).json({ error: "Internal Server Error" });

  }

});

// 验证 JWT 中间件,在需要验证的路由前使用

const verifyToken = (req, res, next) => {

  const token = req.headers["authorization"]?.split(" ")[1];

  if (!token) {

    return res.status(401).json({ message: "No token provided" });

  }

  // 检查是否在黑名单中

  Blacklist.findOne({ token }, (err, blacklistedToken) => {

    if (err) {

      return res.status(500).json({ error: "Internal Server Error" });

    }

    if (blacklistedToken) {

      return res.status(401).json({ message: "Token has been revoked" });

    }

    jwt.verify(token, secretKey, (err, decoded) => {

      if (err) {

        return res.status(401).json({ message: "Invalid token" });

      }

      req.user = decoded;

      next();

    });

  });

};

// 示例受保护的路由

app.get("/protected", verifyToken, (req, res) => {

  res.json({ message: "This is a protected route", user: req.user });

});

// 启动 Express 服务器

app.listen(port, () => {

  console.log(`Server is running on port ${port}`);

});
相关推荐
Msshu1236 小时前
Type-C 多协议快充诱骗电压芯片XSP28 芯片脚耐压高达21V 电路简单 性价比高
mongodb·zookeeper·rabbitmq·flume·memcache
想摆烂的不会研究的研究生6 小时前
每日八股——Redis(1)
数据库·经验分享·redis·后端·缓存
码熔burning7 小时前
MySQL 8.0 新特性爆笑盘点:从青铜到王者的骚操作都在这儿了!(万字详解,建议收藏)
数据库·mysql
猫头虎7 小时前
2025最新OpenEuler系统安装MySQL的详细教程
linux·服务器·数据库·sql·mysql·macos·openeuler
哈库纳玛塔塔7 小时前
放弃 MyBatis,拥抱新一代 Java 数据访问库
java·开发语言·数据库·mybatis·orm·dbvisitor
@LetsTGBot搜索引擎机器人9 小时前
2025 Telegram 最新免费社工库机器人(LetsTG可[特殊字符])搭建指南(含 Python 脚本)
数据库·搜索引擎·机器人·开源·全文检索·facebook·twitter
计算机毕设VX:Fegn08959 小时前
计算机毕业设计|基于springboot + vue动物园管理系统(源码+数据库+文档)
数据库·vue.js·spring boot·后端·课程设计
冉冰学姐9 小时前
SSM校园排球联赛管理系统y513u(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面
数据库·ssm 框架应用·开题报告、
Tony Bai10 小时前
【分布式系统】03 复制(上):“权威中心”的秩序 —— 主从架构、一致性与权衡
大数据·数据库·分布式·架构
wb0430720111 小时前
SQL工坊不只是一个ORM框架
数据库·sql