当前位置: 首页 > article >正文

Express + MongoDB 实现用户登出

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

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

<!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`)

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` 中添加登出路由

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

});


http://www.kler.cn/a/565541.html

相关文章:

  • DDD 架构之领域驱动设计【通俗易懂】
  • 从零开始用react + tailwindcs + express + mongodb实现一个聊天程序(二)
  • 【洛谷贪心算法题】P1094纪念品分组
  • 10分钟熟练掌握宝兰德中间件部署 iServer
  • Starrocks入门(二)
  • 深度剖析 Video-RAG:厦门大学和罗切斯特大学联合推出的一种用于长视频理解的检索增强生成技术
  • 基于大数据的音乐网站数据分析与可视化推荐系统
  • HTML邮件的制作以及遇到的问题
  • Qt常用控件之多行输入框QTextEdit
  • RabbitMQ系列(四)基本概念之Exchange
  • 行为型模式 - 职责链模式 (Chain of Responsibility Pattern)
  • 我与Swagger-UI的量子纠缠:SpringBoot3.x中的薛定谔404事件——解决`springdoc-openapi:2.8.5`UI界面显示问题
  • 【Python pro】函数
  • redis密码设置
  • 如何实现某短视频平台批量作品ID的作品详情采集
  • PySide(PyQT)重新定义contextMenuEvent()实现鼠标右键弹出菜单
  • 销售易NeoCRM与八骏科技CRM:全方位深度对比
  • 浅聊RocketMQ 分布式事务解决方案原理
  • Spock框架:让单元测试更优雅的高效武器
  • QT 读取sqlite3数据库中文乱码