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

Node.js中处理登出请求时销毁JsonWebToken的方案

JWT登出销毁与失效问题解答

1. JWT是否存储在客户端?

是,JWT属于无状态令牌,服务端生成后只会返回给客户端,由客户端自行存储(常见存储位置是localStorage、sessionStorage、前端状态管理库或内存变量),服务端不会保存令牌本身,仅在验证请求时用密钥校验令牌的签名和有效期。

2. 如何销毁JWT并让后续请求失效?

因为服务端不存储令牌,没法直接从服务端销毁,需要客户端+服务端配合处理:

客户端处理(核心操作)

当用户触发登出请求时,客户端必须主动清除存储的JWT:

  • 存在localStorage时:localStorage.removeItem('x-access-token')
  • 存在sessionStorage时:sessionStorage.removeItem('x-access-token')
  • 存在前端状态管理库(如Vuex/Redux)或内存变量时:直接将对应的token字段置空

这样后续请求就不会携带有效令牌,自然会被服务端的authenticateToken中间件拦截。

服务端补充方案(防范未过期令牌冒用)

你当前设置的令牌有效期是1年,太长了——如果用户登出后令牌还没过期,可能被冒用。这时候可以用令牌黑名单机制:

  1. 用Redis这类支持自动过期的存储(读写效率高),在用户登出时,将该JWT存入黑名单,并设置和令牌本身一致的过期时间。
  2. 修改你的authenticateToken中间件,在校验令牌有效后,先检查令牌是否在黑名单中,在的话直接返回401。

修改后的中间件示例:

// 先初始化Redis客户端(需提前安装redis依赖)
const redis = require('redis');
const client = redis.createClient();

module.exports = middlewares = {
  authenticateToken: async (req, res, next) => {
    try {
      if (!req.headers["x-access-token"]) {
        return res.status(401).json({
          error: "Key x-access-token not found",
        });
      }

      const token = req.headers["x-access-token"];
      if (token === "") {
        return res.status(401).json({
          error: "Token not found",
        });
      }

      // 先检查令牌是否在黑名单
      const isBlacklisted = await client.get(`blacklist:${token}`);
      if (isBlacklisted) {
        return res.status(401).json({ error: "Token has been revoked" });
      }

      const data = jwt.verify(token, keys.JWToken);
      req.data = data;

      next();
    } catch (err) {
      return res.status(400).json({ error: err.message });
    }
  },
};

登出接口示例:

app.post('/logout', async (req, res) => {
  const token = req.headers["x-access-token"];
  if (!token) {
    return res.status(200).json({ message: "Logout successful" });
  }
  
  // 获取令牌剩余有效期,设置黑名单过期时间和令牌一致
  const decoded = jwt.decode(token);
  const expiresIn = decoded.exp - Math.floor(Date.now() / 1000);
  
  await client.setEx(`blacklist:${token}`, expiresIn, 'true');
  res.status(200).json({ message: "Logout successful" });
});

额外优化建议

  • 缩短Access Token有效期:把expiresIn改成15分钟到1小时,配合Refresh Token机制——登录时返回一个有效期较长的Refresh Token(比如7天),当Access Token过期时,用Refresh Token换取新的Access Token,既保证安全又不影响用户体验。
  • 客户端存储选型:单页应用尽量用内存存储(如状态管理库),避免用localStorage,减少XSS攻击导致令牌被盗的风险。

内容的提问来源于stack exchange,提问作者John Oliver

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 14:36:52