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

Express+Jsonwebtoken+TypeScript认证中间件失效问题求助

TypeScript下jsonwebtoken认证中间件失效问题修复

问题重现

基于jsonwebtoken库实现的认证中间件切换为TypeScript后,抛出"Invalid token, authorisation denied"错误,但将认证逻辑直接写入路由时却能正常运行。

原中间件代码

import { NextFunction, Request, Response } from "express";
import jwt, { Secret } from "jsonwebtoken";

const SECRET_KEY: Secret = String(process.env.SECRET_KEY);
const AUTHORISATION: boolean = Boolean(process.env.AUTHORISATION) || true;

export default function (req: Request, res: Response, next: NextFunction) {
  if (!AUTHORISATION) next();
  const token = <string>req.headers["x-auth-token"];
  if (!token) {
    return res.status(401).json({ msg: "No token, authorisation denied" });
  }
  try {
    jwt.verify(token, SECRET_KEY, function (err, decoded) {
      if (err) {
        console.log(err);
        return res.status(401).json({ msg: "Invalid token, authorisation denied" });
      }
      next();
    });
  } catch (err) {
    res.status(401).json({ msg: "Authentication error" });
  }
}

控制台错误日志

SyntaxError: Unexpected token v in JSON at position 0
    at JSON.parse (<anonymous>)
    at Object.jwsDecode [as decode] (D:\projects\heroes\server\node_modules\jws\lib\verify-stream.js:71:20)
    at module.exports (D:\projects\heroes\server\node_modules\jsonwebtoken\decode.js:5:21)
    at Object.module.exports [as verify] (D:\projects\heroes\server\node_modules\jsonwebtoken\verify.js:76:20)
    at default_1 (D:\projects\heroes\server\middleware\auth.ts:14:9)
    at Layer.handle [as handle_request] (D:\projects\heroes\server\node_modules\express\lib\router\layer.js:95:5)
    at next (D:\projects\heroes\server\node_modules\express\lib\router\route.js:144:13)
    at Route.dispatch (D:\projects\heroes\server\node_modules\express\lib\router\route.js:114:3)
    at Layer.handle [as handle_request] (D:\projects\heroes\server\node_modules\express\lib\router\layer.js:95:5)
    at D:\projects\heroes\server\node_modules\express\lib\router\index.js:284:15

问题原因

  1. 认证关闭逻辑未终止后续代码:当AUTHORISATION为false时,调用next()后未添加return,导致后续的token检查代码仍会执行,引发不必要的错误。
  2. 异步回调版本的验证逻辑缺陷:原中间件使用jwt.verify的异步回调版本,该版本的错误不会向外层try/catch抛出,且内部错误处理逻辑易因token解析异常触发报错;而路由中使用的同步版本能被try/catch正确捕获,逻辑更稳定。

修复后的中间件代码

import { NextFunction, Request, Response } from "express";
import jwt, { Secret, JwtPayload } from "jsonwebtoken";

// 扩展Express Request类型,方便后续路由获取解析后的用户信息(可选)
declare global {
  namespace Express {
    interface Request {
      user?: JwtPayload | string;
    }
  }
}

const SECRET_KEY: Secret = process.env.SECRET_KEY as Secret;
// 优化环境变量判断,避免非布尔值误判
const AUTHORISATION: boolean = process.env.AUTHORISATION !== "false";

export default function authMiddleware(req: Request, res: Response, next: NextFunction) {
  // 关闭认证时直接放行,终止后续逻辑
  if (!AUTHORISATION) {
    return next();
  }

  const token = req.headers["x-auth-token"] as string;
  if (!token) {
    return res.status(401).json({ msg: "No token, authorisation denied" });
  }

  try {
    // 使用同步版本的jwt.verify,与路由验证逻辑保持一致
    const decoded = jwt.verify(token, SECRET_KEY) as JwtPayload;
    // 将解析后的用户信息挂载到req对象,供后续路由使用
    req.user = decoded;
    next();
  } catch (err) {
    console.error(err);
    res.status(401).json({ msg: "Invalid token, authorisation denied" });
  }
}

关键修复点说明

  • 终止未认证场景的后续逻辑:在关闭认证的分支中添加return,确保不会执行后续的token检查代码。
  • 改用同步版验证逻辑:同步版本的jwt.verify错误能被外层try/catch捕获,逻辑更简洁,且与路由中的验证逻辑保持一致,避免异步回调带来的异常处理问题。
  • 类型与环境变量处理优化:使用as替代尖括号类型断言(TypeScript推荐写法),优化环境变量判断逻辑,避免空字符串等非布尔值被误判为true。
  • 扩展Request类型:方便后续路由直接获取解析后的用户信息,提升代码易用性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 00:12:13