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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 05:32:42