Apollo Server v4集成Express:req.user传递与JWT中间件异常
问题1:解决TypeScript报错“Property 'user' does not exist on type 'Request'”
你已经尝试用custom.d.ts扩展Express的Request类型,但大概率是配置或写法有误,按以下步骤修正:
- 确保
custom.d.ts被TypeScript识别:在tsconfig.json的include数组中添加该文件,示例配置:{ "include": ["src/**/*", "custom.d.ts"] } - 正确编写类型扩展代码:如果文件处于模块环境(包含
import/export),需要将声明包裹在global命名空间中,同时添加export {}让文件成为模块避免冲突:// custom.d.ts declare global { namespace Express { interface Request { // 根据你的JWT payload定义字段,比如id、邮箱等 user?: { id: string; email?: string }; } } } export {}; - 重启TypeScript语言服务(比如VS Code中重新加载窗口),让新类型生效。
问题2:JWT中间件未执行的原因及解决方法
Apollo Server v4与Express集成时,中间件的挂载顺序直接决定是否生效,且Apollo的expressMiddleware会接管请求处理,你之前的问题大概率是顺序错误或验证位置不对:
方法1:在Express层面挂载中间件(确保顺序正确)
- 先挂载JWT中间件,再挂载Apollo的
expressMiddleware,保证请求先经过验证再进入GraphQL处理流程:import { expressMiddleware } from '@apollo/server/express4'; import jwt from 'jsonwebtoken'; import { Request, Response, NextFunction } from 'express'; // 定义JWT验证中间件 const jwtMiddleware = (req: Request, res: Response, next: NextFunction) => { console.log('执行JWT验证'); // 现在应该能看到日志输出 const authHeader = req.headers.authorization; if (authHeader && authHeader.startsWith('Bearer ')) { const token = authHeader.slice(7); try { req.user = jwt.verify(token, process.env.JWT_SECRET!) as { id: string }; } catch (err) { console.error('Token验证失败:', err); } } next(); // 必须调用next()让请求继续流转到Apollo }; // 先挂载JWT中间件 app.use('/graphql', jwtMiddleware); // 再挂载Apollo的expressMiddleware app.use( '/graphql', cors(), express.json(), expressMiddleware(server, { context: async ({ req }) => ({ user: req.user }), // 将验证后的user传入Apollo上下文 }), ); - 核心注意点:中间件必须在
expressMiddleware之前挂载,Express按顺序执行中间件,顺序颠倒会导致JWT验证被跳过。
方法2:直接在Apollo的Context里处理JWT验证(更推荐)
无需单独编写Express中间件,直接在Apollo的context函数中完成验证,更贴合GraphQL架构:
import { expressMiddleware } from '@apollo/server/express4'; import jwt from 'jsonwebtoken'; await server.start(); app.use( '/graphql', cors(), express.json(), expressMiddleware(server, { context: async ({ req }) => { console.log('执行JWT验证'); let user = null; const authHeader = req.headers.authorization; if (authHeader && authHeader.startsWith('Bearer ')) { const token = authHeader.slice(7); try { user = jwt.verify(token, process.env.JWT_SECRET!) as { id: string }; } catch (err) { console.error('Token验证失败:', err); } } return { user }; // 将user传入所有Resolver的context参数 }, }), );
之后在Resolver中就能通过context.user获取验证后的用户信息,示例:
const resolvers = { Query: { me: async (_, __, { user }) => { if (!user) throw new Error('未授权'); // 从数据库查询用户信息 return await User.findById(user.id); }, }, };
内容的提问来源于stack exchange,提问作者CodeConnoisseur
相关产品推荐
相关产品推荐

