繁体   English   中英

如何在 NestJs 中仅在特定情况下使 guard 可选?

[英]How to make guard optional only in particular case in NestJs?

我在 NestJS 中有以下两个守卫(一个用于基于 api 密钥的身份验证,另一个用于基于令牌的身份验证)。ApiKeyGuard 是重中之重。我想实现一个系统,如果有人有钥匙,它不会检查另一个守卫。在有 ApiKeyGuard 的情况下,有什么方法可以根据第一个 Guard 是否通过来使 AuthGuard 可选?

// Can be accessed with token within app as well as third party users
    @UseGuards(ApiKeyGuard, AuthGuard)
    @Get('/get-products')
      async getProducts(): Promise<any> {
        try {
          return this.moduleRef
            .get(`appService`, { strict: false })
            .getProducts();
        } catch (error) {
          throw new InternalServerErrorException(error.message, error.status);
        }
    
      }

// Only to be accessed with token within app
    @UseGuards(AuthGuard)
    @Get('/get-users')
      async getUsers(): Promise<any> {
        try {
          return this.moduleRef
            .get(`appService`, { strict: false })
            .getUsers();
        } catch (error) {
          throw new InternalServerErrorException(error.message, error.status);
        }
    
      }

下面的守卫用于检查基于 api 密钥的身份验证

api-key.guard.ts

@Injectable()
export class ApiKeyGuard implements CanActivate {
  constructor(private readonly apiKeyService: ApiKeyService) {} 

  async canActivate(context: ExecutionContext): Promise<boolean> {
    const req = context.switchToHttp().getRequest();
    const key = req.headers['X-API-KEY'] ?? req.query.api_key;
    return this.apiKeyService.isKeyValid(key);
  }

下面的守卫用于检查基于令牌的身份验证

        authentication.guard.ts
        
        @Injectable()
        
        export class AuthGuard implements CanActivate, OnModuleInit {
          constructor(private readonly moduleRef: ModuleRef) {}
          onModuleInit() {}
          async canActivate(context: ExecutionContext): Promise<boolean> {
        
            try {
        
              // Get request data and validate token
        
              const request = context.switchToHttp().getRequest();
        
              if (request.headers.authorization) {
                const token = request.headers.authorization.split(' ')[1];
                const response = await this.checkToken(token);
           
                if (response) {
                  return response;
                } else {
                  throw new UnauthorizedException();
                }
              } else {
                throw new UnauthorizedException();
              }
        
            } catch (error) {
              throw new UnauthorizedException();
            }
        
          }
        
        }

我所做的是使用@nestjs/passport并使用AuthGuard并制定自定义 PassportJS 策略。 我有一个类似的问题,并寻找一种方法来完成这个而不使用一些“魔法”。 可以在此处找到文档

AuthGuard中,您可以添加多个守卫。 它有点隐藏在文档中,尽管它非常强大。 看看这里,尤其是该部分的最后一行,它指出:

除了扩展默认的错误处理和认证逻辑外,我们还可以通过一系列策略允许对 go 进行认证。 第一个成功、重定向或错误的策略将停止链。 身份验证失败将依次通过每个策略,如果所有策略都失败,则最终失败。

可以这样做:

export class JwtAuthGuard extends AuthGuard(['strategy_jwt_1', 'strategy_jwt_2', '...']) { ... }

现在,回到您的示例,您必须创建 2 个自定义策略,一个用于 API 密钥,一个用于授权 header,这两个守卫都应该被激活。

所以对于 API 策略(例如):

import { Strategy } from 'passport-custom';
import { Injectable } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { Strategy } from 'passport-custom';
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';

@Injectable()
export class ApiStrategy extends PassportStrategy(Strategy, 'api-strategy') {
  constructor(private readonly apiKeyService: ApiKeyService) {} 

  async validate(req: Request): Promise<User> {
    const key = req.headers['X-API-KEY'] ?? req.query.api_key;
    if ((await this.apiKeyService.isKeyValid(key)) === false) {
      throw new UnauthorizedException();
    }

    return this.getUser();
  }
}

为您的其他身份验证方式做类似的事情,然后按如下方式使用 Passport guard:

@UseGuard(AuthGuard(['api-strategy', 'other-strategy'])

这样,守卫将尝试所有策略(按顺序),当所有策略都失败时,您的身份验证失败。 如果其中之一成功,则您已通过身份验证!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM