NestJS:如何在REQUEST作用域提供者初始化前修改请求?
解决NestJS REQUEST作用域提供者初始化前修改请求的问题
针对你遇到的REQUEST作用域提供者无法获取Guard处理后用户信息的问题,有几个可行的方案:
方案一:用Node.js AsyncLocalStorage存储用户信息
这个方案绕开直接依赖请求对象的限制,在请求最早期的中间件中存储认证信息,供后续提供者读取:
- 首先创建一个单例的AsyncLocalStorage实例作为提供者:
import { AsyncLocalStorage } from 'async_hooks'; import { Injectable } from '@nestjs/common'; @Injectable() export class RequestContext { private readonly als = new AsyncLocalStorage<Map<string, any>>(); startContext() { return this.als.run(new Map(), () => {}); } set(key: string, value: any) { const store = this.als.getStore(); if (store) store.set(key, value); } get<T>(key: string): T | undefined { const store = this.als.getStore(); return store?.get(key) as T; } } - 编写全局中间件,在其中完成Passport认证并将用户存入AsyncLocalStorage:
import { Injectable, NestMiddleware } from '@nestjs/common'; import { Request, Response, NextFunction } from 'express'; import { RequestContext } from './request-context.service'; import passport from 'passport'; @Injectable() export class AuthMiddleware implements NestMiddleware { constructor(private readonly requestContext: RequestContext) {} async use(req: Request, res: Response, next: NextFunction) { // 启动ALS上下文 this.requestContext.startContext(); // 执行Passport认证逻辑 await new Promise((resolve, reject) => { passport.authenticate('jwt', { session: false }, (err, user) => { if (err) return reject(err); if (user) this.requestContext.set('user', user); resolve(null); })(req, res, resolve); }); next(); } } - 在REQUEST作用域提供者的useFactory中,通过AsyncLocalStorage获取用户:
{ provide: 'DYNAMIC_SERVICE', useFactory: async (requestContext: RequestContext) => { const user = requestContext.get('user'); // 用user配置动态实例 return new DynamicService(user); }, inject: [RequestContext], scope: Scope.REQUEST, }
方案二:直接使用Passport全局中间件
跳过NestJS的Guard层,在应用启动时直接挂载Passport的认证中间件,这个中间件的执行时机早于所有NestJS内置的请求处理逻辑,包括REQUEST作用域提供者的初始化:
// 在main.ts中 async function bootstrap() { const app = await NestFactory.create(AppModule); // 直接挂载Passport认证中间件 app.use(passport.authenticate('jwt', { session: false })); await app.listen(3000); } bootstrap();
这样请求进来后会先完成认证,用户信息被挂载到req.user,之后REQUEST作用域提供者的useFactory中就能直接从req对象读取到用户信息。
方案三:调整依赖注入顺序(不推荐)
如果你的REQUEST作用域提供者是被注入到控制器或其他晚于Guard执行的组件中,可以尝试将提供者的依赖改为REQUEST作用域的守卫实例,但这种方式依赖NestJS的注入顺序,稳定性较差,不推荐在生产环境使用。
内容的提问来源于stack exchange,提问作者Gdfelt
相关产品推荐
相关产品推荐

