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

});
相关推荐
CJi0NG18 分钟前
【自用】MySQL-多表查询
数据库·mysql
雨落在了我的手上24 分钟前
MySQL数据库基础(12):事务
数据库·mysql
D姐聊门店27 分钟前
门店收银系统断网兜底怎么设计:本地账本、离线续传与日终对账的工程实现
数据库·saas
用户8662978480081 小时前
抓包看 KingbaseES 内部协议?官方给了个现成工具
数据库
wefg11 小时前
【Redis】安装与启动
数据库·redis·缓存
大圣编蚕1 小时前
常见的 Redis 面试题(高频整理)
数据库·redis·缓存
派小心.2 小时前
网站统计采样数据的误差核对
大数据·服务器·前端·数据库·人工智能·小程序·数据分析
龙腾AI白云2 小时前
数字孪生、具身智能、世界模型三者交叉
数据库·人工智能·机器学习·flask·pygame
SelectDB技术团队2 小时前
Apache Doris 基于 Lance 的向量检索深度解析
数据库·数据仓库·数据分析·湖仓一体·apache doris·lakehouse·多模湖仓
这个DBA有点耶3 小时前
从INDEX到JOIN_ORDER:MySQL 8.0 Hint语法体系与五类实战场景
数据库·mysql·架构