Express TypeScript中间件报错:jwt.verify() is not a function
问题:TypeScript环境下Express JWT中间件报错
TypeError: jwt.verify is not a function 原本基于JavaScript开发的Express JWT认证中间件(通过Access/Refresh Token实现用户认证)运行正常,迁移到TypeScript后,出现TypeError: jwt.verify is not a function错误。
相关代码
认证中间件代码
import { UserJWTPayload } from '../interfaces/UserJWTPayload' import { NextFunction, Request, Response } from 'express' import { ResponseObject } from '../api/classes/ResponseObject' import SequelizeApi from '../sequelize/sequelize-api' import * as jwt from 'jsonwebtoken' const authenticateUserTokens = async (req: Request, res: Response, next: NextFunction) => { try { const accessToken: string = req.cookies.access_token const refreshToken: string = req.cookies.refresh_token if (!accessToken || !refreshToken) return res.status(401).json(new ResponseObject(false, 'not authenticated', null)) console.log(jwt) /* [Module: null prototype] { decode: [Function (anonymous)], default: { decode: [Function (anonymous)], verify: [Function (anonymous)], sign: [Function (anonymous)], JsonWebTokenError: [Function: JsonWebTokenError], NotBeforeError: [Function: NotBeforeError], TokenExpiredError: [Function: TokenExpiredError] } } */ console.log(jwt.verify()) /* export function verify(token: string, secretOrPublicKey: Secret, options?: VerifyOptions & { complete?: false }): JwtPayload | string; An argument for 'token' was not provided */ console.log(jwt.verify(accessToken, process.env.JWT_ACCESS_TOKEN_PRIVATE_KEY)) /* TypeError: jwt.verify is not a function at file:///C:/Users/Jakub/Desktop/Projekty/StoriesBatchApi/src/middlewares/authenticate-user-tokens.ts:16:25 at Generator.next (<anonymous>) at file:///C:/Users/Jakub/Desktop/Projekty/StoriesBatchApi/src/middlewares/authenticate-user-tokens.ts:7:71 at new Promise (<anonymous>) at __awaiter (file:///C:/Users/Jakub/Desktop/Projekty/StoriesBatchApi/src/middlewares/authenticate-user-tokens.ts:3:12) at file:///C:/Users/Jakub/Desktop/Projekty/StoriesBatchApi/src/middlewares/authenticate-user-tokens.ts:7:96 at Layer.handle [as handle_request] (C:\Users\Jakub\Desktop\Projekty\StoriesBatchApi\node_modules\express\lib\router\layer.js:95:5) at next (C:\Users\Jakub\Desktop\Projekty\StoriesBatchApi\node_modules\express\lib\router\route.js:144:13) at Route.dispatch (C:\Users\Jakub\Desktop\Projekty\StoriesBatchApi\node_modules\express\lib\router\route.js:114:3) at Layer.handle [as handle_request] (C:\Users\Jakub\Desktop\Projekty\StoriesBatchApi\node_modules\express\lib\router\layer.js:95:5) */ const accessTokenData = jwt.verify(accessToken, process.env.JWT_ACCESS_TOKEN_PRIVATE_KEY) as UserJWTPayload const refreshTokenFromDatabase = await SequelizeApi.getModel('user_token').findOne({ where: { refresh_token: refreshToken } }) if (!refreshTokenFromDatabase) return res.status(401).json(new ResponseObject(false, 'invalid refresh token', null)) jwt.verify(refreshToken, process.env.JWT_REFRESH_TOKEN_PRIVATE_KEY) res.locals.id_user = accessTokenData.id_user return next() } catch (e) { console.error(e) return res.status(401).json(new ResponseObject(false, 'server error | not authenticated', e.message)) } }; export default authenticateUserTokens
受保护路由代码
userRouter.delete('/:id', authenticateUserTokens(), async (req, res) => { try { const deletedUserId = parseInt(req.params.id) const actionByUserId = parseInt(res.locals.id_user) if (actionByUserId !== deletedUserId) return res.status(403).json(new ResponseObject(false, 'not authorized', null)) const arrayOfAffectedRows = await userModel.update({ status: 'deleted' }, { where: { id: deletedUserId } }) if (arrayOfAffectedRows[0] === 1) return res.status(200).json(new ResponseObject(true, 'user deleted', null)) else return res.status(404).json(new ResponseObject(false, 'user not found', null)) } catch(e) { return res.status(500).json(new ResponseObject(false, 'server error', e)) } })
tsconfig.json配置
{ "compilerOptions": { "module": "ES6", "removeComments": true, "target": "es6", "rootDir": "./", "esModuleInterop": true, "moduleResolution":"node", }, "include": [ "src/**/*" ], "exclude": [ "node_modules" ] }
启动命令
nodemon -r dotenv/config --experimental-specifier-resolution=node --esm src/server.ts
问题原因
从控制台打印的jwt模块结构可以明确看到:verify等核心方法实际挂载在jwt.default属性下。这是因为jsonwebtoken是CommonJS模块,在ES模块环境(你的配置中module: ES6且启用--esm)下导入时,CommonJS的默认导出会被包装到ES模块的default属性中。而TypeScript的类型定义让你误以为可以直接调用jwt.verify,但运行时该方法并不存在于顶级模块对象上。
另外,路由代码中authenticateUserTokens()的写法是错误的——中间件不需要立即执行,应该传递函数引用,否则中间件会在路由注册时就执行,而非请求到达时执行。
解决方案
1. 修正JWT导入方式(推荐)
将导入语句改为直接导入默认导出,这样可以直接调用jwt.verify:
import jwt from 'jsonwebtoken'
2. 保留原导入,修改调用方式
如果坚持使用import * as jwt,则所有调用都要通过default属性:
// 替换所有jwt.verify为jwt.default.verify const accessTokenData = jwt.default.verify(accessToken, process.env.JWT_ACCESS_TOKEN_PRIVATE_KEY) as UserJWTPayload jwt.default.verify(refreshToken, process.env.JWT_REFRESH_TOKEN_PRIVATE_KEY)
3. 修正路由中间件引用
将路由中的authenticateUserTokens()改为authenticateUserTokens,传递函数引用而非执行结果:
userRouter.delete('/:id', authenticateUserTokens, async (req, res) => { // ... 原路由逻辑 })
内容的提问来源于stack exchange,提问作者Jakub
相关产品推荐
相关产品推荐

