如何在控制器中忽略来自 @UseGuards() 的某些路由?

RAM*_*RAM 3 nestjs

我有一个这样的控制器:

@ApiBearerAuth()
@UseGuards(AuthGuard('jwt'))
@ApiTags('books')
@Controller('books')
export class BooksController {

  @Post()
  async create(@Body() createBookVm: CreateBookVm) {
    //........
  }

  @Get()
  async all() {
    //........
  }
}
Run Code Online (Sandbox Code Playgroud)

当我在没有 accessToken 的情况下访问all()上述控制器中的 rout 时,出现以下错误:

{"statusCode":401,"error":"Unauthorized"}
Run Code Online (Sandbox Code Playgroud)

这是正确的行为,但我想忽略控制器all()一般的操作。@UseGuards我想在未经授权的情况下将其作为公共路线访问。

小智 5

假设您使用了main.tsapp.useGlobalGuards()文件中的方法,请在auth.guard.ts文件中添加以下代码:

import { ExecutionContext, Injectable } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { AuthGuard as PassportAuthGaurd } from '@nestjs/passport';

@Injectable()
export class AuthGuard extends PassportAuthGaurd('jwt') {
  constructor(private readonly reflector: Reflector) {
    super();
  }

  canActivate(context: ExecutionContext) {
    const isPublic = this.reflector.get<boolean>(
      'isPublic',
      context.getHandler()
    );

    if (isPublic) {
      return true;
    }

    return super.canActivate(context);
  }
}
Run Code Online (Sandbox Code Playgroud)

我在这里使用了 pssport jwt 方法,但你可以根据你的需要改变它,只要记住保持构造函数和canActivate的逻辑相同即可。现在在你的main.ts中修改全局防护,以便我们可以在其中使用Reflector :

const reflector = app.get(Reflector);
app.useGlobalGuards(new AuthGuard(reflector));
Run Code Online (Sandbox Code Playgroud)

现在,为了使路由公开,我们将使用自定义装饰器,为此创建一个名为public.decorator.ts的文件并添加以下代码:

import { SetMetadata } from '@nestjs/common';
export const Public = () => SetMetadata('isPublic', true);
Run Code Online (Sandbox Code Playgroud)

在这里,我们添加了一个自定义元数据值,该值与我们在auth.guard.ts文件中使用的值相同。现在只需在您想要公开的路由上添加这个@Public()装饰器即可:

 @Get()
 @Public()
  async all() {
    //........
  }
Run Code Online (Sandbox Code Playgroud)

现在您的 all 函数将不会检查令牌身份验证。我发现这个博客做了同样的事情,你可以看看。