守卫

守卫根据运行时出现的某些条件(例如权限,角色,访问控制列表等)来确定给定的请求是否由路由处理程序处理,这通常称为授权

在传统的Express应用程序中,通常由中间件处理授权(以及认证);中间件是身份验证的良好选择,因为诸如token验证或添加属性到request对象上与特定路由(及其元数据)没有强关联

守卫在每个中间件之后执行,在任何拦截器或管道之前执行

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

使用守卫

创建一个守卫:

1
nest g gu [name]

创建后:

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

@Injectable()
export class RoleGuard implements CanActivate {
canActivate(
context: ExecutionContext,
): boolean | Promise<boolean> | Observable<boolean> {
return true;
}
}

Controller使用守卫

使用@UseGuards应用守卫

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import {
Controller,
Get,
UseGuards,
} from '@nestjs/common';
import { GuardService } from './guard.service';
import { RoleGuard } from './role/role.guard';

@Controller('guard')
// 使用路由守卫
@UseGuards(RoleGuard)
export class GuardController {
constructor(private readonly guardService: GuardService) {}

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

全局守卫

在main.ts中注册全局守卫

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import { NestFactory } from '@nestjs/core';
import { VersioningType } from '@nestjs/common';
import { AppModule } from './app.module';
import { NestExpressApplication } from '@nestjs/platform-express';
import { RoleGuard } from './guard/role/role.guard';

async function bootstrap() {
const app = await NestFactory.create<NestExpressApplication>(AppModule, {
cors: true,
});
app.enableVersioning({
type: VersioningType.URI,
});
// 使用全局守卫
app.useGlobalGuards(new RoleGuard());
await app.listen(3000);
}
bootstrap();

针对角色控制守卫

在Controller定义元信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import {
Controller,
Get,
UseGuards,
SetMetadata,
} from '@nestjs/common';
import { GuardService } from './guard.service';
import { RoleGuard } from './role/role.guard';

@Controller('guard')
@UseGuards(RoleGuard)
export class GuardController {
constructor(private readonly guardService: GuardService) {}

@Get()
// 设置元信息键值
// 此处的含义是定义role(角色)信息,如果符合对应角色才允许访问
@SetMetadata('role', ['admin'])
findAll() {
return this.guardService.findAll();
}
}

在守卫安排判断逻辑:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
import { Observable } from 'rxjs';
import { Reflector } from '@nestjs/core';
import type { Request } from 'express';

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

canActivate(
context: ExecutionContext,
): boolean | Promise<boolean> | Observable<boolean> {
// 得到角色列表(元信息,键是role)
const admin = this.Reflector.get<string[]>('role', context.getHandler());
// 得到此次请求的request
const req = context.switchToHttp().getRequest<Request>();
// 得到请求中的role参数
const role = req.query.role;
// 判断role参数的角色是否符合访问要求
if (admin.includes(role as string)) {
return true;
} else {
return false;
}
}
}

角色不符合权限:

角色符合权限: