nestjs守卫

一.基本概念

1、作用?

守卫是一个使用Injectable装饰器所装饰的类,并且implements了CanActivate这个interface,守卫一般用来进行权限判断。

2、如何使用脚手架创建守卫?

1
nest g guard name

3、如何创建守卫?

代码举例如下所示:

1
2
3
4
5
6
7
8
9
10
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
import { Observable } from 'rxjs';

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

也就是说,对于一个守卫guard类来说,必须使用Injectable装饰器进行装饰,必须implements接口CanActivate,必须实现canActive类方法。

4、如何使用守卫?

可以对整个controller类应用守卫,如下所示:

1
2
3
4
5
6
7
8
import { Controller, UseGuards } from '@nestjs/common';
import { RolesGuard } form '../guard/roles.guard';

@Controller('/news')
@UseGuards(RolesGuard)
export class NewsController {

}

也可以只针对controller类中的某一个路由方法应用守卫,如下所示:

1
2
3
4
5
6
7
8
9
10
11
import { Controller, UseGuards, Get, Query } from '@nestjs/common';
import { RolesGuard } from '../guard/roles.guard';

@Controller('/news')
export class NewsController {
@Get('topic')
@UseGuards(RolesGuard)
getHotNews(@Query() queryObj) {

}
}

也可以配置一个全局守卫,如下所示:

1
2
3
4
// main.ts
import { RolesGuard } from './guards/roles.guard';

app.useGlobalGuards(new RolesGuard()); // 很奇怪,这里需要传入实例对象

配置全局守卫还有下面这种方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
// app.module.ts
import { Module } form '@nestjs/common';
import { APP_GUARD } form '@nestjs/core';
import { RolesGuard } from './guard/roles.guard';

@Module({
providers: [
{
provide: APP_GUARD,
useClass: RolesGuard,
}
]
})

注意,在使用UseGuards装饰器的时候,参数既可以是guard类也可以是guard实例。

5、守卫应用后有什么效果?

前面也提到了,守卫最终会返回布尔值,守卫在接收到了request,进入到controller路由之前被执行,如果guard返回true的话,那么路由正常执行;如果guard返回false的话,那么返回403状态码,controller中的路由方法得不到运行机会。

6、应用了全局守卫后,如果不想某些路由被守卫拦截的话该怎么做?

举例如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
import { Observable } from 'rxjs';

@Injectable()
export class AuthGuard extends CanActivate {
canActivate(context: ExecutionContext): bool | Promise<boolean> | Observable<boolean> {
const request = context.switchToHttp().getRequest();
const whiteList = ['/login', 'index'];
const path = request.path;
if (whiteList.includes(path)) return true;
// 接下来可以做验证逻辑
}
}