在 NestJS 中,有没有办法将数据从 Guards 传递到控制器?

Posted

技术标签:

【中文标题】在 NestJS 中,有没有办法将数据从 Guards 传递到控制器?【英文标题】:In NestJS is there any way to pass data from Guards to the controller? 【发布时间】:2020-03-02 00:16:24 【问题描述】:

所以我目前在我的组织中广泛使用 NestJS。出于身份验证的目的,我们使用自己的警卫。所以我的问题是,除了 expressjs 的response.locals 之外,如果有任何方法可以将数据从警卫传递到控制器,那么任何人都可以指导我吗?这造成了对框架的硬依赖,我现在不希望这样。

TIA。

【问题讨论】:

【参考方案1】:

将数据从 Guard 传递到 Controller 的唯一方法是将数据附加到请求中的字段或使用某种元数据反射,这可能变得比其价值更具挑战性。

你可以有一个canActivate这样的函数

canActivate(context: ExecutionContext): boolean | Promise<boolean> | Observable<boolean> 
  const req = context.switchToHttp().getRequest();
  if (/* some logic with req */) 
    req.myData = 'some custom value';
  
  return true;

然后在您的控制器中,您可以拉出req.myData 并取回some custom value 字符串。

【讨论】:

您好,杰伊,感谢您的回答。这可行,但这是一种解决方法,response.locals 有点相同,这东西不优雅,绝对不可读。 你试图从守卫传递什么数据到控制器? Passport 的做法(来自中间件,不是守卫,但同样的想法)是将其附加到req.user。除此之外,或者可能试图进行一些聪明/棘手的反射元数据设置,没有其他方法。守卫在那里返回真或假(或它的异步变体),以便系统知道是继续请求还是返回错误代码。 > 然后在你的控制器中你可以拉req.myData...那在控制器中究竟会是什么样子? 此外,您可以创建自定义装饰器来简化访问 req.myData 对象的过程。【参考方案2】:

您可以创建自定义装饰器来获取数据,而不是使用 Guard:

export const Authorization = createParamDecorator((_, request: any) => 
  const  authorization: accessToken  = request.headers;
  try 
    const decoded = jwt.verify(accessToken, process.env.JWT_HASH);
    return pick(decoded, 'userId');
   catch (ex) 
    throw new InvalidToken();
  
);

export interface AuthUser 
  userId: string;

然后像这样传递给你的控制器:

  @Post()
  createFeedback(
    @Body() body: FeedbackBody,
    @Authorization() user: AuthUser,
  ): Promise<Feedback> 
    body.userId = user.userId;
    return this.feedbackService.feedback(body, user);
  

这可以起到保护作用,因为当你的令牌无效时,它会抛出异常

【讨论】:

所以基本上它只是通过body 本身传输userId。所以这意味着大多数@Body 事件函数都需要这种形式的授权。【参考方案3】:

正如其他人所说,您可以在警卫上传递请求对象上的数据,但通过 @Req 装饰器接收它们并不理想,特别是如果您对请求对象没有任何其他用途。您可以创建一个自定义装饰器,该装饰器将检索您想要的数据并将它们注入任何控制器

【讨论】:

以上是关于在 NestJS 中,有没有办法将数据从 Guards 传递到控制器?的主要内容,如果未能解决你的问题,请参考以下文章

有没有办法从NestJS应用程序中收集所有方法及其路径?

将@ApiQuery 与nestJS 和swagger 一起使用时,有没有办法声明默认值?

NestJS:有没有办法从外部调用微服务rabbitmq

测试中的 NestJS 全局模块

有没有办法在没有 typeorm 的情况下创建 NestJS API,但使用普通的 expressJS/mysql 方法?

所有控制器的全局标头(nestJs swagger)