1. 什么是守卫
Nest.js 中的守卫(Guard)是一种特殊类型的中间件,可以用于保护路由,控制谁可以访问某个路由。守卫是用来验证请求是否有权限进行请求的,如果请求有权限,守卫会让请求通过到达路由处理程序;如果请求没有权限,守卫会拒绝请求,并返回特定的 HTTP 响应。
Nest.js 守卫能够进行基于角色、权限、访问令牌等多种验证方式,常常用于鉴权和授权操作。守卫可以在路由处理程序执行之前或之后拦截请求,并在验证通过或不通过后执行一些操作,例如记录日志、重定向或抛出异常。
在 Nest.js 中,守卫可以是全局的或局部的,如果是全局的,那么它将适用于应用程序中的所有路由,如果是局部的,那么它只适用于特定的路由。守卫也可以链式调用,允许多个守卫共同验证请求。
守卫的执行顺序
守卫的执行顺序取决于它们在路由处理管道中的位置。在 Nest.js 中,请求会经过一系列处理管道,包括守卫、中间件和控制器的顺序调用。
路由处理管道的顺序如下:
- 全局守卫:全局守卫按照它们在应用程序模块中提供程序的位置顺序执行,先执行模块中最后注册的全局守卫,再执行模块中前面注册的全局守卫。
- 中间件:中间件按照它们在模块中注册的顺序执行,先执行模块中注册的最后一个中间件,再执行模块中前面注册的中间件。
- 路由守卫:路由守卫按照它们在路由中定义的顺序执行,先执行路由定义中最后一个守卫,再执行前面定义的守卫。
- 控制器方法:控制器方法按照它们在控制器类中定义的顺序执行,先执行类定义的最后一个方法,再执行前面定义的方法。
守卫在控制器方法之前执行,而拦截器则在控制器方法执行前后执行,它们的处理顺序为:路由守卫 > 全局守卫 > 拦截器 > 中间件 > 控制器方法 > 响应拦截器。
守卫种类
AuthGuard:保护路由的基本守卫,用于验证用户是否已经通过身份验证。RolesGuard:用于验证用户是否有足够的角色来执行某个操作。JwtAuthGuard:基于 JSON Web Tokens(JWT)进行身份验证的守卫。ThrottlerGuard:用于限制请求数量和请求速率,防止恶意攻击。RateLimitGuard:基于令牌桶算法实现的流量限制守卫,可以控制请求的频率和速率。
2. 守卫的方式
2.1 局部守卫
先生成一个role的守卫 nest g gu role
role.guard.ts
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> {
console.log('打印***context 守卫', context);
return true;
}
}
guard.controller.ts
import { RoleGuard } from './role.guard';
@Controller('guard')
@UseGuards(RoleGuard)
export class GuardController {}
2.2 全局守卫
main.ts
import { RoleGuard } from './guard/role.guard';
app.useGlobalGuards(new RoleGuard())
举例:
guard.controller.ts
import {
Controller,
Get,
UseGuards,
SetMetadata,
} from '@nestjs/common';
import { GuardService } from './guard.service';
import { RoleGuard } from './role.guard';
@Controller('guard')
@UseGuards(RoleGuard)
export class GuardController {
constructor(private readonly guardService: GuardService) {}
@Get()
@SetMetadata('role', ['admin']) // 自定义名称 数据
findAll() {
return this.guardService.findAll();
}
}
取数据时用定义的键 role取
role.guard.ts
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> {
console.log('打印***context 守卫', context);
const admin = this.reflector.get<string[]>('role', context.getHandler()); // [ 'admin' ]
// ?role=admin 进行定义 有就访问
const req = context.switchToHttp().getRequest<Request>();
console.log(req.query.role);
if (admin.includes(req.query.role as string)) {
return true;
} else {
return false;
}
}
}
访问 http://localhost:3000/guard?role=admfj