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
问题原因
- 认证关闭逻辑未终止后续代码:当
AUTHORISATION为false时,调用next()后未添加return,导致后续的token检查代码仍会执行,引发不必要的错误。 - 异步回调版本的验证逻辑缺陷:原中间件使用
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
相关产品推荐
相关产品推荐

