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

});
相关推荐
代码or搬砖1 小时前
SQL核心语法总结:从基础操作到高级窗口函数
java·数据库·sql
1 小时前
TIDB——TIKV——读写与coprocessor
数据库·分布式·tidb·
大猫和小黄2 小时前
若依微服务全面适配PostgreSQL-OpenGauss数据库
数据库·微服务·postgresql·若依
老徐电商数据笔记2 小时前
技术复盘第二篇:电商数据主题域划分企业级实践
大数据·数据库·数据仓库·零售·教育电商·技术面试
jfqqqqq2 小时前
postgres查询、重设自增序列的起始值
数据库·sql·postgres·自增序列
2 小时前
TIDB——PD(placement Driver)
java·数据库·分布式·tidb·
DemonAvenger2 小时前
Redis与MySQL双剑合璧:缓存更新策略与数据一致性保障
数据库·redis·性能优化
断春风2 小时前
如何避免 MySQL 死锁?——从原理到实战的系统性解决方案
数据库·mysql
闲人编程2 小时前
基础设施即代码(IaC)工具比较:Pulumi vs Terraform
java·数据库·terraform·iac·codecapsule·pulumi
QQ_21696290963 小时前
Spring Boot大学生社团管理平台 【部署教程+可完整运行源码+数据库】
java·数据库·spring boot·微信小程序