【NestJS】Guard 守卫


守卫一般用于授权处理,判断当前请求是否能放行给路由处理程序。

执行顺序:中间件 - 守卫 - 拦截器 / 管道



使用守卫

  1. 创建 CRUD 模板:nest g res cus-guard
  2. 创建守卫:nest g gu cus-guard
import {
    
     CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
import {
    
     Observable } from 'rxjs';

@Injectable() // 守卫也是使用 @Injectable() 修饰;  需要继承自 CanActivate
export class CusGuardGuard implements CanActivate {
    
    
    // 需要实现 canActivate 方法;  该方法接收参数 ctx, 返回布尔值
    canActivate(
        context: ExecutionContext,
    ): boolean | Promise<boolean> | Observable<boolean> {
    
    
        console.log('经过了守卫');
        return true; // 返回 truely 值表示放行, 否则当前请求会被拦截
    }
}
  1. 通过 @UseGuards(XXX) 装饰器使用守卫
import {
    
     Controller, Get, UseGuards } from '@nestjs/common';
import {
    
     CusGuardGuard } from './cus-guard.guard';
import {
    
     CusGuardService } from './cus-guard.service';

@Controller('cus-guard')
@UseGuards(CusGuardGuard) // 使用守卫
export class CusGuardController {
    
    
    constructor(private readonly cusGuardService: CusGuardService) {
    
    }

    @Get()
    findAll() {
    
    
        return this.cusGuardService.findAll();
    }
}

如果需要使用多个守卫,可以给 UseGuards 传入多个参数:@UseGuards(XXX, XXX, XXX)。守卫会从左往右执行。若前面的守卫没有放行,则不会执行后面的守卫。


也可以把守卫放到指定方法前,表示只有这个方法需要鉴权

@Controller('cus-guard')
export class CusGuardController {
    
    
    constructor(private readonly cusGuardService: CusGuardService) {
    
    }

    @Get()
		@UseGuards(CusGuardGuard) // 使用守卫
    findAll() {
    
    
        return this.cusGuardService.findAll();
    }
}



全局守卫

  1. 创建守卫:nest g gu cus-guard
  2. 使用 useGlobalGuards 注册全局守卫
import {
    
     NestFactory } from '@nestjs/core';
import {
    
     AppModule } from './app.module';
import {
    
     CusGuardGuard } from './cus-guard/cus-guard.guard'; // 引入守卫

async function bootstrap() {
    
    
    const app = await NestFactory.create(AppModule);
    app.useGlobalGuards(new CusGuardGuard()); // 注册全局守卫
    await app.listen(3000);
}
bootstrap();



配置角色权限

  1. 使用装饰器 @SetMetadata(key, value) 配置角色
import {
    
     Controller, Get, UseGuards, SetMetadata } from '@nestjs/common';
import {
    
     CusGuardGuard } from './cus-guard.guard';
import {
    
     CusGuardService } from './cus-guard.service';

@Controller('cus-guard')
@UseGuards(CusGuardGuard)
export class CusGuardController {
    
    
    constructor(private readonly cusGuardService: CusGuardService) {
    
    }

    @Get()
    @SetMetadata('role', ['admin']) // 注入数据
    findAll() {
    
    
        return this.cusGuardService.findAll();
    }
}
  1. 使用反射 Reflector 读取 SetMetadata 的值
import {
    
     CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
import {
    
     Reflector } from '@nestjs/core';
import {
    
     Observable } from 'rxjs';

@Injectable()
export class CusGuardGuard implements CanActivate {
    
    
    constructor(private reflector: Reflector) {
    
    } // 注入 Reflector 实例

    canActivate(
        context: ExecutionContext,
    ): boolean | Promise<boolean> | Observable<boolean> {
    
    
        // 通过 Reflector 实例的 get 方法获取被注入的数据
        const role = this.reflector.get<string[]>('role', context.getHandler());
        console.log('role', role);
        return true;
    }
}

现在请求 /cus-guard 会在服务端打印 role [ 'admin' ]


假设我们通过 query 参数携带权限信息,我们需要根据该权限信息进行授权:

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

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

    canActivate(
        context: ExecutionContext,
    ): boolean | Promise<boolean> | Observable<boolean> {
    
    
        const role = this.reflector.get<string[]>('role', context.getHandler());
        const req = context.switchToHttp().getRequest<Request>(); // 获取请求
        const cusRole = req.query.role as string; // 获取 query 参数 role
        const permission = role.includes(cusRole); // 判断权限
        console.log('permission', permission);
        return permission;
    }
}

img


不携带 query 参数 role / role 值不为 'admin',都会抛出 403 ( Forbidden referer origin )

img

猜你喜欢

转载自blog.csdn.net/Superman_H/article/details/129171808