概念
顾名思义,守卫
根据运行时出现的某些条件(权限,角色,访问控制列表等)来确定给定的请求是否交给对应的路由处理程序。
- 守卫是一个使用
@Injectable()装饰器的类
,实现了CanActive
接口。 -
Express
中通常用中间件处理授权(身份验证),优点是token验证或将request对象附加属性与特定路由没有强关联。缺点是中间件不知道调用next()之后的处理程序。 -
守卫
可以在请求-响应周期的正确位置插入处理逻辑。守卫在每个中间件之后
,在任何拦截器/管道之前
执行。
授权守卫
经过身份验证的请求(请求头附加了token),授权守卫
将提取和验证token,并使用提取的信息来确认请求是否可以继续。
import { Injectable, CanActive, ExecutionContext } from '@nestjs/common';
import { Observable } from 'rxjs';
@Injectable()
export class AuthGuard implements CanActive {
canActive(
context: ExecutionContext
): boolean | Promise<boolean> | Observable<boolean> {
const request = context.switchToHttp().getRequest();
return validateRequest(request);
}
}
-
validateRequest()
函数中的逻辑可简单可复杂。必须返回一个布尔值。可同步或异步(Promise/Observable)返回响应。
执行上下文
export interface ExecutionContext extends ArgumentsHost {
getClass<T = any>(): Type<T>;
getHandler(): Function;
}
-
getHandler()
方法返回对将要调用的处理程序的引用 -
getClass()
方法返回这个特定处理程序所属的 Controller 类的类型
角色认证
//允许所有请求继续
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
import { Observable } from 'rxjs';
@Injectable()
export class RolesGuard implements CanActivate {
canActivate(
context: ExecutionContext,
): boolean | Promise<boolean> | Observable<boolean> {
return true;
}
}
绑定守卫
@Controller('cats')
//@UseGuards(new RolesGuard())
@UseGuards(RolesGuard) //控制器范围的守卫
export class CatsController {}
-
@UseGuard()装饰器
可以接受单个或逗号分隔的多个参数 - 守卫可以使方法层面,控制器层面,全局层面
反射器
根据执行上下文
为不同的路由提供不同的权限方案;
Nest
使用@SetMetadata()装饰器
将定制元数据附加到路由处理程序,守卫根据提供的角色数据,做出决策。
//roles.decorator.ts
import { SetMetadata } from '@nestjs/common';
export const Roles = (...roles: string[]) => SetMetadata('roles', roles);
//cats.controller.ts
@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);
}
}
- 根据分配给当前用户的角色与正在处理的当前路由所需的实际角色之间的比较来设置返回值的条件。
- 为了访问路由的角色(自定义元数据),我们将使用在 @nestjs/core 中提供的 Reflector 帮助类
网友评论