NestJs - 守卫

72 阅读1分钟

守卫是一个用 @Injectable() 装饰器注释的类,它实现了 CanActivate 接口。

守卫在 controller 之前执行,它的职责是单一的。它根据运行时的某些条件判断是否将请求交给路由程序处理。

canActivate 函数接收一个 context 参数,它的类型是 ExecutionContext。它扩展了 ArgumentsHost 类型。canActivate 函数的返回值为布尔类型(同步 boolean、异步 Promise<boolean>)。当返回 true,请求会被处理,返回 false 请求将会被拒绝。

import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
import { Observable } from 'rxjs';

@Injectable()
export class AuthGuard implements CanActivate {
  canActivate(
    context: ExecutionContext,
  ): boolean | Promise<boolean> | Observable<boolean> {
    const request = context.switchToHttp().getRequest();
    return validateRequest(request);
  }
}

守卫传惨

守卫可以通过自定义元数据传递参数。通过内置 Reflector 类创建装饰器,并注入数据,然后在守卫中获取对应数据处理。

import { Reflector } from '@nestjs/core';

export const Roles = Reflector.createDecorator<string[]>();
@Post()
@Roles(['admin'])
async create(@Body() createCatDto: CreateCatDto) {
  this.catsService.create(createCatDto);
}
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { Roles } from './roles.decorator';

@Injectable()
export class RolesGuard implements CanActivate {
  constructor(private reflector: Reflector) {}

  canActivate(context: ExecutionContext): boolean {
    // getHandler 函数获取当前请求所对应的处理器,即被调用的控制器方法。
    const roles = this.reflector.get(Roles, context.getHandler());
    if (!roles) {
      return true;
    }
    const request = context.switchToHttp().getRequest();
    const user = request.user;
    return matchRoles(roles, user.roles);
  }
}