even

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

1、nest.js中session的使用

介绍:session 是另一种记录客户状态的机制,不同的是 Cookie 保存在客户端浏览器中,而 session 保存 在服务器上

工作流:当浏览器访问服务器并发送第一次请求时,服务器端会创建一个 session 对象,生成一个类似于 key,value 的键值对,然后将 key(cookie)返回到浏览器(客户)端,浏览器下次再访问时,携带 key(cookie), 找到对应的 session(value)。 客户的信息都保存在 session 中

具体文档:https://docs.nestjs.com/techniques/session

安装

npm i express-session --save
npm i -D @types/express-session --save

引入和配置(main.ts)

import * as session from 'express-session'

app.use(session({
  secret: 'this is secret key',
  cookie: {
    maxAge: 6000,
    httpOnly: true
  },
  rolling: true   //表示在每次请求时强行设置 cookie,这将重置 cookie 过期时间
}))

使用方式

import { Controller, Get, Req, Session  } from '@nestjs/common';
import { YfService } from './yf.service';

@Controller('yf')
export class YfController {
    public constructor(private yfservice: YfService) {}

    @Get()
    public index(@Session() session: Record<string, any>) {
        session.name = 'this is session test'
        return 'this is test'
    }

    @Get('cookie')
    public getCookie(@Session() session: Record<string, any>): string {
        return session.name;
    }
}

注意:也可以通过request.session进行存储与读取

session配置的常用方法

app.use(session({
    resave: false,
    saveUninitialized: true,
    secret: '12345',
    name: 'name',
    cookie: {maxAge: 60000},
    resave: false,
    saveUninitialized: true
}));

参数说明

secret: 一个 String 类型的字符串,作为服务器端生成 session 的签名。

name: 返回客户端的 key 的名称,默认为 connect.sid,也可以自己设置。

resave:强制保存 session 即使它并没有变化,。默认为 true。建议设置成 false。 don't save session if unmodified

saveUninitialized:强制将未初始化的 session 存储。当新建了一个 session 且未设定属性或值时,它就处于 未初始化状态。在设定一个 cookie 前,这对于登陆验证,减轻服务端存储压力,权限控制是有帮助的。(默 认:true)。建议手动添加。

cookie: 设置返回到前端 key 的属性,默认值为{ path: ‘/’, httpOnly: true, secure: false, maxAge: null }。

rolling: 在每次请求时强行设置 cookie,这将重置 cookie 过期时间(默认:false)

常用方法

req.session.destroy(function(err) { /*销毁 session*/
})
req.session.username='张三'; //设置 session
req.session.username //获取 session
req.session.cookie.maxAge=0; //重新设置 cookie 的过期时

也可以使用装饰器删除

2、nest.js文件上传

 单文件上传

import {
  Controller,
  Get,
  Post,
  UseInterceptors,
  UploadedFile
} from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';
import { createWriteStream } from 'fs';
import { join } from 'path';

@Controller('upload')
export class UploadController {
  @Get()
  public index() {
    return 'this is upload test';
  }

  @Post('addfile')
  @UseInterceptors(FileInterceptor('file'))  //这里面的file是表示<input type='file' name='file'>里的name用axios上传默认是file
  public addFile(@UploadedFile() file) { // 获取参数的UploadedFile装饰器
    const writeImage = createWriteStream(
      join('public/upload', `${file.originalname}`) //注意这里没有/的路径是指定根目录下的public目录
    );
    writeImage.write(file.buffer);
    return { data: 'ok' };
  }
}

注意:如果进行表单文件上传,那么一定要添加属性 enctype="multipart/form-data"

前端代码

<template>
  <div class="upload-demo">
    <input
      type="file"
      ref="fileInt"
      @change="changeHandle"
    />
  </div>
</template>

<script>
import { getInfo } from '@/api/login'
import { setToken, getToken } from '@/utils/auth'

export default {
  name: 'login',
  methods: {
    changeHandle() {
      const file = this.$refs.fileInt.files[0]
      console.log(file)
      const data = new FormData()
      data.append('file', file) //注意:这里相当于指定了name
      getInfo(data)
        .then((res) => {
          console.log(res)
        })
        .catch((err) => {
          console.log(err)
        })
    },
  },
}
</script>

<style scoped></style>

请求

import request from '@/utils/request'

export const getInfo = (data) => {
  return request({
    url: '/upload/addfile',
    method: 'post',
    data,
    Headers: {
      'Content-Type': 'multipart/form-data',
    },
    onUploadProgress: function(progressEvent) {
      const complete = parseInt(
        ((progressEvent.loaded / progressEvent.total) * 100) | 0
      )
      // 这里为上传的进度
      console.log(complete)
    },
    // onDownloadProgress //下载
  })
}

附带请求流数据的写法(axios案例)

const downloadResource = async (url: string, progress?: (progressEvent: ProgressEvent) => void) => {
    let {data} = await httpClient.request<ArrayBuffer>({
        method: 'get',
        url: encodeURI(url),
        responseType: 'arraybuffer',
        onDownloadProgress(progressEvent) {
            console.log(progressEvent);
            // 下载进度数据
            if (progress) progress(progressEvent);
        },
    });
    fs.writeFileSync(join(getUploadCachePath(), basename(url)), Buffer.from(data));
};

注意:上面写法是在文件数据全部请求完整后再进行写入,这期间会占用浏览器的内存,如果文件的空间占用不大则问题不大,如果文件比较大建议使用以下的方式进行下载

axios
  .get(
    'https://xxx.zip',
    {
      responseType: 'stream',
      onDownloadProgress(ev) {
        console.log(ev);
      },
    },
  )
  .then((res: Stream) => {
    res.pipe(fs.createWriteStream('dist/test.zip'));
res.on('error', () => {// 执行错误的操作})
res.on('end', () => {
// 执行下载完成的操作
}) });

注意:如果没有用input file进行选择文件,那么就需要用fs文件系统进行读取文件

private async uploadComponent(path: string) {
    const file = new FormData();  // 可以用new File来模拟file文件
    let buffer = readFileSync(path);  // 这个是从fs-extra中获取的方法
    file.append('file', new Blob([buffer.buffer])); // 或者使用new File进行转换上传
    //通过发送ajax请求进行上传
    。。。
}

多文件上传

import {
  Controller,
  Get,
  Post,
  UseInterceptors,
  UploadedFiles
} from '@nestjs/common';
import {
  FilesInterceptor,
  AnyFilesInterceptor,
  FileFieldsInterceptor
} from '@nestjs/platform-express';
import { createWriteStream } from 'fs';
import { join } from 'path';

@Controller('upload')
export class UploadController {
  @Get()
  public index() {
    return 'this is upload test';
  }

  @Post('addfile')
  @UseInterceptors(FilesInterceptor('file')) //如果多文件使用的是一个名称
  // @UseInterceptors(AnyFilesInterceptor()) //如果多文件使用的是一个名称
  // @UseInterceptors(FileFieldsInterceptor([  // 如果指定的是多个名称的,那么需要按如下配置
  //   { name: 'avatar', maxCount: 1 },
  //   { name: 'background', maxCount: 1 },
  // ]))
  public addFile(@UploadedFiles() file) {
    // 获取参数的UploadedFile装饰器
    file.forEach(val => {
      const writeImage = createWriteStream(
        join('public/upload', `${val.originalname}`) //注意这里没有/的路径是指定根目录下的public目录
      );
      writeImage.write(val.buffer, err => {
        if (err) console.log(err);
      });
      writeImage.end(() => {
        console.log('end');
      });
    });
    return { data: 'ok' };
  }
}

前端代码

<template>
  <div class="upload-demo">
    <input
      type="file"
      ref="fileInt"
      @change="changeHandle"
      multiple="multiple"
    />
  </div>
</template>

<script>
import { getInfo } from '@/api/login'
import { setToken, getToken } from '@/utils/auth'

export default {
  name: 'login',
  methods: {
    changeHandle() {
      const file = this.$refs.fileInt.files
      console.log(file)
      const data = new FormData()
      file.forEach((val) => {
        data.append('file', val)
      })
      // data.append('file', file)
      getInfo(data)
        .then((res) => {
          console.log(res)
        })
        .catch((err) => {
          console.log(err)
        })
    },
  },
}
</script>

request请求的代码不变

如果前端得到后端的数据是{type: Buffer, data: [...]}那么用如下方法进行转换成文件

const len = value.data.length;

const buf = new ArrayBuffer(len);

const view = new Uint8Array(buf);

value.data.forEach((value, key) => {
    view[key] = value;
});

let contentUrl = window.URL.createObjectURL(new Blob([buf]));

let link = document.createElement('a');

link.href = contentUrl;

link.setAttribute('download', 'text.txt'); // 文件名称,这里很重要,如果没有完整的文件名(包括扩展名),下载下来还需要自行添加

document.body.appendChild(link);

link.click();

window.URL.revokeObjectURL(contentUrl);

 3、nest.js的中间件

在nest中, 中间件就是匹配路由之前或者匹配路由完成做的一系列的操作。中间件中如果想往下 匹配的话,那么需要写 next()

中间件的创建命令

nest g middleware middleware/init  // 表示在middleware的文件夹下创建initMiddleware中间件

类的中间件

import { Injectable, NestMiddleware } from '@nestjs/common';
import { Response } from 'express';

@Injectable()
export class InitMiddleware implements NestMiddleware {  //在类的中间件中需要实现NestMiddleware接口,并且实现里面的use方法
  use(req: any, res: Response, next: () => void) {  // 接收三个参数,req, res, next,如果需要向下执行,需要调nest()方法,否则请求会被挂起
    console.log('this is test');
    next();
  }
}

函数中间件

// 函数式中间件接收三个参数
export const logger = (req: Request, res: Response, next: () => void) => {
  console.log('this is logger');
  next();
};

中间件的注册(需要注册到model里,model需要实现NestModule的接口)

import { Module, NestModule, MiddlewareConsumer } from '@nestjs/common';
import { LoggerMiddleware } from './common/middleware/logger.middleware';
import { CatsModule } from './cats/cats.module';

@Module({
  imports: [CatsModule],
})
export class AppModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {
    consumer
      .apply(LoggerMiddleware) //应用LoggerMiddleware中间件
      .forRoutes('cats/:catName'); //指定中间件的应用路径/cats/:catName  
      //.forRoutes('cats');
    
      //也可以通过如下方式指定包含中间件的请求方法
      // .forRoutes({ path: 'cats', method: RequestMethod.GET });
    
      //也可以使用通配符来匹配路径,如以下示例
      //forRoutes({ path: 'ab*cd', method: RequestMethod.ALL });
    
     // 通过以下方法来针对不同控制器使用中间件,也可以传递一个由逗号分隔的控制器列表
     //.forRoutes(CatsController);
    
     // 通过exclude和路径方法来排除特定路径
     //.exclude(
     //{ path: 'cats', method: RequestMethod.GET },
     //{ path: 'cats', method: RequestMethod.POST })
     
  }
}

 调用多个中间件

consumer.apply(InitMiddleware, logger).forRoutes('*');

注册全局中间件

const app = await NestFactory.create(AppModule);
app.use(logger); // 目前测试这个只支持函数式中间件
await app.listen(3000);

4、nest.js中管道(pipe)的使用

 管道(Pipes)是一个用 @Injectable() 装饰过的类,它必须实现 PipeTransform 接口。

 

从官方的示意图中我们可以看出来管道 pipe 和过滤器 filter 之间的关系:管道偏向于服务端控制器逻辑,过滤器则更适合用客户端逻辑。

过滤器在客户端发送请求处理,管道则在控制器接收请求处理。

管道通常有两种作用:

  • 转换/变形:转换输入数据为目标格式

  • 验证:对输入数据时行验证,如果合法让数据通过管道,否则抛出异常。

目前nest.js中内置了两个验证的类ParseIntPipe 与 ParseUUIDPipe具体使用如下

@Get(':id')
public getParamData(
  @Query('age', ParseIntPipe) query,
  @Param('id', new ParseIntPipe({ errorHttpStatusCode: HttpStatus.GONE }))
  param
) {
  console.log(query, param);
  return 'this is getParamData';
}

自定义管道

创建自定义管道

nest g pipe pipe/parseTestPipe

 使用joi库进行验证

$ npm install --save joi
$ npm install --save-dev @types/joi

新建管道

import {
  ArgumentMetadata,
  Injectable,
  PipeTransform,
  BadRequestException
} from '@nestjs/common';

@Injectable()
export class ParseTestPipe implements PipeTransform {
  public constructor(private readonly schema) {} // schema是外面传入的joi对象

  transform(value: any, metadata: ArgumentMetadata) { // 可以从metadata文件中获取验证的数据类型,是body, query, param, custom
    console.log(metadata);
    if (metadata.type === 'query') { //也可以把类型通过传参的形式传递
      const { error } = this.schema.validate(value);
      console.log(error);
      if (error) {
        throw new BadRequestException('Validation failed');
      }
    }
    return value; //如果数据没有问题,那么返回,验证处程序可以正常往下跑
  }
}

例如下面的写法

import {
  ArgumentMetadata,
  Injectable,
  PipeTransform,
  BadRequestException
} from '@nestjs/common';

@Injectable()
export class ParseTestPipe implements PipeTransform {
  public constructor(private readonly schema, private readonly type?) {} // schema是外面传入的joi对象

  transform(value: any, metadata: ArgumentMetadata) {
    // 可以从metadata文件中获取验证的数据类型,是body, query, param, custom
    console.log(this.type);
    if (!this.type || metadata.type === this.type) {
      const { error } = this.schema.validate(value);
      console.log(error);
      if (error) {
        throw new BadRequestException('Validation failed');
      }
    }
    return value;
  }
}

控制器调用的写法

import { Controller, Get, Param, Query, UsePipes } from '@nestjs/common';
import { ParseTestPipe } from 'src/pipe/parse-test-pipe.pipe';
import * as Joi from 'joi';

const schema = Joi.object({ //joi的验证对象
  name: Joi.string().required(),
  age: Joi.number().required()
});

@Controller('test')
export class TestController {
  @Get()
  public index() {
    return 'this is test';
  }

  @Get(':id')
  @UsePipes(  //这里可以传一个参数,也可以传两个参数
    new ParseTestPipe(schema, 'query'),
    new ParseTestPipe(Joi.number().required(), 'param')
  )
  public getParamData(@Query() query, @Param('id') param) {
    console.log(query, param);
    return 'this is getParamData';
  }
}

注意:如果在usePipes里面的类型检测没有指定检测对象的话,默认会进行全部检测

类验证器

需要安装依赖

npm i --save class-validator class-transformer

对类验证器的扩展依赖

npm i --save @nestjs/mapped-types

 在dtos文件下新建验证文件User.dto.ts

import { IsNumber, IsString, IsNumberString } from 'class-validator';
import {
  PickType,
  OmitType,
  PartialType,
  IntersectionType
} from '@nestjs/mapped-types';

export class UserDto {
  @IsString()
  public name: string;

  @IsNumberString()
  public age: number;

  @IsNumber()
  public id: number;
}

//表示从UserDto中继承了一些属性进行验证
export class PickUserDto extends PickType(UserDto, ['name', 'age'] as const) {}

//表示从UserDto中继承除了id的所有属性进行验证
export class OmitUserDto extends OmitType(UserDto, ['id'] as const) {}

//表示继承所有属性,但是所有属性都是可选的,相当于只验证正确性,不验证存在性
export class PartialUserDto extends PartialType(UserDto) {}

//把指定的两个类合并继承,那么就拥有了两个类的所有属性
export class IntersectionDto extends IntersectionType(PickUserDto, OmitUserDto) {}

使用示例

import { Type } from 'class-transformer';
import { IsArray, IsUUID, Length, ValidateIf, ValidateNested } from 'class-validator';
import { CourseIdDto } from './course.dto';

// 页面id验证
export class PageIdDto {
    @IsUUID('all', { message: '请传入合法的page id' })
    public id: string;
}

export class PageInfoDto extends PageIdDto {
    @Length(1, 50, { message: '课程名称需要在1-50个字符内' })
    public name: string;

    @IsUUID('all', { message: '请传入合法的asset id' })
    public asset: string;

    @IsUUID('all', { message: 'next的id不合法' })
    @ValidateIf((object: any, value: any) => !!value) // 如果next Id为空或者是uuid
    public next: string;

    @IsUUID('all', { message: 'timeline的id不合法' })
    @ValidateIf((object: any, value: any) => !!value) // 如果next Id为空或者是uuid
    public timeline: string;

    @ValidateIf((object: any, value: any) => value && value.length !== 0) // 如果next Id为空或者是uuid
    @IsArray() // 较验数组里的每一项
    @IsUUID('all', { each: true, message: 'branches里的数据不合法,该数值为页面的uuid' })
    public branches: Array<string>;
}

export class CourseAddPageDto extends CourseIdDto {
    @IsArray({ message: 'pages需要是一个页面数组' })
    @ValidateNested()
    @Type(() => PageInfoDto)
    public pages: PageInfoDto[];
}

也可以使用正则进行匹配

export class TestItemDto {
    @Matches(/^https?/i)
    @IsNotEmpty()
    href: string;
}

在框架中引用的方式

方法一,在需要使用的方法中引入

@Post()
async create(
  @Body(new ValidationPipe()) userDto: UserDto,
) {
  this.userService.create(UserDto);
}

方法二,使用装饰器引入

  @Get(':id')
  @UsePipes(
    new ValidationPipe({
      transform: true
    })
  )
  public getParamData(@Query() query: PartialUserDto, @Param('id') param) {
    console.log(query, param);
    return 'this is getParamData';
  }

方法三,在全局进行引入

import { NestFactory } from '@nestjs/core';
import { NestExpressApplication } from '@nestjs/platform-express';
import { AppModule } from './app.module';
import { ValidationPipe } from '@nestjs/common';

async function bootstrap() {
  const app = await NestFactory.create<NestExpressApplication>(AppModule);

  ...

  //管道验证配置
  app.useGlobalPipes(
    new ValidationPipe({
      transform: true
    })
  );

  await app.listen(3000);
}
bootstrap();

注意:ValidationPipe里的配置可以查看官网  https://docs.nestjs.com/techniques/validation   class-validator的使用方法  https://www.npmjs.com/package/class-validator

可以对数据验证的报错信息进行修改

import { CustomError } from '@app/errors/custom.error';
import { ResponseStatus } from '@app/interfaces/response.interface';
import { ValidationError, ValidationPipe, ValidationPipeOptions, HttpStatus } from '@nestjs/common';
import { HttpErrorByCode } from '@nestjs/common/utils/http-error-by-code.util';

export default class CustomValidationPipe extends ValidationPipe {
    public constructor(options: ValidationPipeOptions) {
        super(options);
    }

    public createExceptionFactory(validationErrors?: ValidationError[]) {
        return (validationErrors = []) => {
            if (this.isDetailedOutputDisabled)
                return new HttpErrorByCode[this.errorHttpStatusCode]();

            const errors = this.flattenValidationErrors(validationErrors);
            return new CustomError(
                { status: ResponseStatus.Error, message: errors[0] },
                this.errorHttpStatusCode || HttpStatus.OK,
            );
        };
    }
}

5、nest.js中Module的使用

模块(Module)是一个使用了 @Module() 装饰的类。@Module() 装饰器提供了一些 Nest 需要使用的元数据,用来组织应用程序的结构。

module的创建

nest g module ***/**/testModule

@Module() 装饰器接收一个参数对象,有以下取值

 

 module的使用

在controllers中定义相关的controller控制器,但是在controller中需要使用的相当的服务, 那么就需要在provides中引入相当的服务,但是如果这个服务在其他的模块,那么为了方便开发,可以使用模块的导入与导出, 需要被共享部份的modules需要导出服务,而引入其他萨法诺娃的modules需要导入服务,具体见下面例子

需要被共享部份的modules

import { Module } from '@nestjs/common';
import { BasicController } from './controllers/basic/basic.controller';
import { UserService } from './services/user/user.service';

@Module({
  controllers: [BasicController],
  providers: [UserService],
  exports: [UserService]  // 服务的导出
})
export class BasicModule {}

需要引入模块的模块

import { UserService } from './../basic/services/user/user.service';
import { YfService } from './../../yf/yf.service';
import { BasicModule } from './../basic/basic.module';
import { NewsService } from './service/news/news.service';
import { Module } from '@nestjs/common';
import { UpgradeController } from './controllers/upgrade/upgrade.controller';

@Module({
  imports: [BasicModule],
  controllers: [UpgradeController],
  providers: [NewsService, YfService]
})
export class UpgradeModule {}

这样就可以在controller中正常的导入服务进行使用了

import { YfService } from './../../../../yf/yf.service';
import { UserService } from './../../../basic/services/user/user.service';
import { NewsService } from './../../service/news/news.service';
import { Controller, Get } from '@nestjs/common';

@Controller('upgrade')
export class UpgradeController {
  public constructor(
    private readonly newsService: NewsService,
    private readonly userService: UserService,
    private readonly yfService: YfService
  ) {}

  @Get()
  public index() {
    return {
      user: this.userService.getInfo(),
      news: this.newsService.getNewsList(),
      other: this.yfService.getAll()
    };
  }
}

 如果一个模块经常被其他模块使用,也就是经常被引用,那么可以考虑设置为全局模块,那么其他模块可以在不引入当前模块的前提下使用该模块

import { Module, Global } from '@nestjs/common';
import { BasicController } from './controllers/basic/basic.controller';
import { UserService } from './services/user/user.service';

@Global()
@Module({
  controllers: [BasicController],
  providers: [UserService],
  exports: [UserService]
})
export class BasicModule {}

 6、nest.js中的守卫

守卫是一个使用 @Injectable() 装饰器的类。 守卫应该实现 CanActivate 接口。

守卫有一个单独的责任。它们确定请求是否应该由路由处理程序处理。到目前为止,访问限 制逻辑大多在中间件内。这样很好,因为诸如 token 验证或将 request 对象附加属性与 特定路由没有强关联。但中间件是非常笨的。它不知道调用 next() 函数后会执行哪个处 理程序。另一方面,守卫可以访问 ExecutionContext 对象,所以我们确切知道将要执行 什么。

说白了:在 Nextjs 中如果我们想做权限判断的话可以在守卫中完成,也可以在中间件中完 成。

文档位置:  https://docs.nestjs.com/guards

创建守卫

nest g guard guard/auth

示例如下

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

@Injectable()
export class AuthGuard implements CanActivate {
  canActivate(
    context: ExecutionContext
  ): boolean | Promise<boolean> | Observable<boolean> {
    return true;  // 如果返回true则会向访问到需要访问的地址,如果返回false那么就会报403错误
  }
}

使用守卫

可以对整个控制器中所有的地址使用,也可以对控制器中指定的方法进行使用

import { NewsService } from './../../service/news/news.service';
import { Controller, Get, UseGuards } from '@nestjs/common';
import { AuthGuard } from 'src/guard/auth.guard';

@Controller('upgrade')
@UseGuards(AuthGuard)  // 如果在controller中使用路由守卫, 那么就会对该控制器下的所有地址执行路由守卫
export class UpgradeController {
  public constructor(private readonly newsService: NewsService) {}

  @Get()
  public index() {
    return {
      news: this.newsService.getNewsList()
    };
  }

  @Get('test')
  @UseGuards(AuthGuard)  // 如果只在方法中使用,那么只对指定的方法指定路由守卫
  public getTest() {
    return 'this is test';
  }
}

在全局中使用路由守卫

const app = await NestFactory.create(AppModule);
app.useGlobalGuards(new RolesGuard());

守卫的参数

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

@Injectable()
export class AuthGuard implements CanActivate {
  canActivate(
    context: ExecutionContext
  ): boolean | Promise<boolean> | Observable<boolean> {
    console.log('执行了守卫');
    console.log(context.switchToHttp().getRequest().cookies);  // 获取cookies
    console.log(context.switchToHttp().getRequest().session);  // 获取session
    console.log(context.switchToHttp().getRequest().path);  // 获取需要访问的路由地址
    return true; // 如果返回true则会向访问到需要访问的地址,如果返回false那么就会报403错误
  }
}

 可以使用SetMetadata配置角色信息

import { SetMetadata } from '@nestjs/common';

export const Roles = (...roles: string[]) => SetMetadata('roles', roles);

使用

@Post()
@Roles('admin')
async create(@Body() createCatDto: CreateCatDto) {
  this.catsService.create(createCatDto);
}

守卫中处理

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

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

  canActivate(context: ExecutionContext): boolean {
    const roles = this.reflector.get<string[]>('roles', context.getHandler());
    if (!roles) {
      return true;
    }
    const request = context.switchToHttp().getRequest();
    const user = request.user;
    return matchRoles(roles, user.roles);
  }
}

注意: 这个配置角色可以和自定义装饰器里的全部导入配合使用,配置@Get(路径)  @Role引用外部的角色路径配置清单实现角色可配置化

 

posted on 2021-07-09 07:22  even_blogs  阅读(977)  评论(0编辑  收藏  举报