在 NestJs 中何时使用守卫以及何时使用中间件

Posted

技术标签:

【中文标题】在 NestJs 中何时使用守卫以及何时使用中间件【英文标题】:When to use guards and when to use middlewares in NestJs 【发布时间】:2020-01-31 10:28:57 【问题描述】:

我想创建一个 NestJs 应用,并希望有一个中间件验证请求对象中的令牌,以及一个身份验证保护来验证令牌有效负载中的用户。

通过拆分这个,我希望能有一个干净的分离。首先是我的中间件

@Injectable()
export class TokenMiddleware implements NestMiddleware 
  use(req: any, res: Response, next: NextFunction) 
    try 
      const headers: IncomingHttpHeaders = req.headers;
      const authorization: string = headers.authorization;
      const bearerToken: string[] = authorization.split(' ');
      const token: string = bearerToken[1];

      // !! Check if token was invalidated !!

      req.token = token;
      req.tokenPayload = verifyToken(token);
      next();
     catch (error) 
      throw new UnauthorizedException();
    
  

它仅验证令牌并使用编码令牌及其有效负载扩展请求对象。我的身份验证卫士

@Injectable()
export class AuthenticationGuard implements CanActivate 
  constructor(private readonly usersService: UsersService) 

  async canActivate(context: ExecutionContext): Promise<boolean> 
    const request: any = context.switchToHttp().getRequest();

    try 
      const user: any = request.tokenPayload;

      if (!user) 
        throw new Error();
      

      const findByIdDTO: FindByIdDTO =  id: user.id ;
      const existingUser: UserRO = await this.usersService.findById(findByIdDTO);

      if (!existingUser) 
        throw new Error();
      

      // attach the user to the request object?

      return true;
     catch (error) 
      throw new UnauthorizedException();
    
  

这个守卫检查 tokenpayload 中提供的用户是否是有效用户。如果一切正常,我应该在哪里将用户附加到请求对象?据我所知,警卫只检查某事是否正确。但我不想将所有这些逻辑保留在令牌中间件中。在 auth guard 中完成验证后,我在哪里可以将数据库用户附加到请求中?

【问题讨论】:

【参考方案1】:

如果你想做类似于 Passport 的事情,你总是可以将用户附加到 req.user,这在 Node.JS 世界中被视为非常标准的设置。

给你的问题是:有什么理由不让两个守卫一个接一个地发挥作用?让一名警卫检查令牌是否存在并且确实是有效的令牌,而一名用于验证令牌上的用户确实是有效的。这样你就不用使用中间件(主要是为了兼容性而包含在内)并且仍然有分离的逻辑。

【讨论】:

【参考方案2】:

Where can I attach the database user to the request after finishing the validation in the auth guard?

我相信,正如您所注意到的,Guard 应该验证给定用户是否有权使用给定方法。

根据你的需要,你可以走不同的路:

1) 使用护照和策略来做你需要做的事情(https://***.com/a/57929429/4319037我已经写了一些关于这个的词和行)。此外,它已经涵盖了提取令牌所需的大部分代码。

@Injectable()
export class HttpStrategy extends PassportStrategy(Strategy) 
  constructor(private readonly authService: AuthService) 
    super()
  

  async validate(token: string) 
    const user = await this.authService.findUserByToken(token);
    if (!user) 
      throw new UnauthorizedException();
    
    return user;
  

2) 在控制器/方法级别使用Interceptor 将用户附加到给定请求(如果缺少令牌则抛出);您的 Guard 将收到 user,因此您可以验证用户是否具有正确的角色/权限来执行该方法。

如果我误解了您想要实现的目标或需要有关特定方式的更多详细信息,请告诉我,谢谢!

【讨论】:

以上是关于在 NestJs 中何时使用守卫以及何时使用中间件的主要内容,如果未能解决你的问题,请参考以下文章

在 C# 中何时使用抽象类以及何时使用接口 [重复]

何时在 Rails 视图中使用 @ 以及何时使用符号?

在 Dart 中何时使用 mixins 以及何时使用接口?

何时使用 viewDidLoad 以及何时使用 awakeFromNib

在 GraphQL 服务器设置中何时使用 Redis 以及何时使用 DataLoader

何时使用 Storyboard 以及何时使用 XIB