作者:markzzw 时间:2024-2-21
线上代码:CodeSandbox
Github:zhangzewei/nest-learning-tutorial
系列阅读 【Nestjs学习日记】专栏
在现代的Web应用程序开发中,安全性和权限管理是至关重要的方面。而Nestjs作为一种强大的Node.js框架,提供了一套灵活而且易于使用的路由守卫机制,用于保护我们的应用程序的特定端点和资源。本文将深入讨论Nestjs中的路由守卫,探索其功能、用法和最佳实践,以帮助您构建安全可靠的Web应用程序。
路由守卫是Nestjs中的重要概念,它允许我们在请求到达控制器之前或之后执行某些操作。这些操作可以涵盖身份验证、授权、数据验证、日志记录等多个方面,以确保只有经过授权的用户能够访问受保护的端点。通过使用路由守卫,我们可以在代码中实现细粒度的访问控制,从而提高应用程序的安全性。
本文将创建一个身份验证的路由守卫并使用它为大家演示nestjs中如何使用路由守卫。
创建一个角色身份守卫
role.guard.ts
ts
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { Roles } from './role.decorator';
@Injectable()
export class RolesGuard implements CanActivate {
constructor(private reflector: Reflector) {}
canActivate(context: ExecutionContext): boolean {
const roles = this.reflector.get(Roles, context.getHandler());
if (!roles) {
return true;
}
const request = context.switchToHttp().getRequest();
console.log(roles);
return roles.includes(request.body.user); // 返回boolean值,true则通过,false则返回报错
}
}
role.decorator.ts
ts
import { Reflector } from '@nestjs/core';
export const Roles = Reflector.createDecorator<string[]>();
使用守卫
在Controller中,为一个路由函数添加守卫,
ts
import { RolesGuard } from './guard/role.guard';
import { Roles } from './guard/role.decorator';
@Controller('app')
export class AppController {
@Post('create')
@Roles(['admin']) // 为当前路由设定权限角色
@UseGuards(RolesGuard) // 使用UseGuards为为当前路由绑定角色权限的守卫
createHello(@Body() body: { name: string; age: string }) {
return `Create hello to ${body.name}, age is ${body.age}`;
}
}
接下来在 postman 中请求这个路由,把角色权限设为user,则会得到403的报错
角色权限设为 admin 则会通过守卫,得到结果
Reflection and metadata
在 NestJS 中,Reflection(反射)和 metadata(元数据)是两个密切相关的概念,用于在运行时动态地获取和操作代码结构。
Reflection(反射):
Reflection 是一种语言特性,允许程序在运行时检查、内省和修改其自身的结构和行为。它提供了对类型信息的运行时访问,例如类、接口、方法、属性及其元数据。通过反射,您可以动态地分析和操作代码元素,例如创建类的新实例、调用方法、访问属性以及检查与代码元素关联的注解或属性。
Reflection 特别适用于需要在运行时动态执行任务或适应未知类型和结构的场景。它使得实现高级功能变得可能,例如依赖注入、动态代码生成和代码解析。
Metadata(元数据):
Metadata 是关于代码元素的附加信息,可以用来描述和注释代码的特性、行为和配置。在 NestJS 中,元数据通常与装饰器(decorators)一起使用。装饰器是用于装饰类、方法、属性或参数的特殊注释,它们可以附加元数据到相应的代码元素上。
通过使用装饰器和元数据,您可以在 NestJS 中实现一些高级功能,例如:
- 依赖注入:通过在类或参数上应用装饰器,您可以指定依赖关系并将它们自动注入到相应的代码中。
- 路由和请求处理:通过在控制器类或处理方法上应用装饰器,您可以指定路由路径、请求方法和中间件等信息。
- 身份验证和授权:通过在路由处理程序或方法上应用装饰器,您可以添加身份验证和授权逻辑,以限制对受保护资源的访问。
NestJS 的反射和元数据机制结合使用,使得开发人员能够以声明性和动态的方式定义和配置应用程序的行为。通过使用装饰器和元数据,您可以更加灵活地组织和管理代码,实现可扩展和可维护的应用程序。
这段代码就是对路由函数进行守卫的绑定匹配
ts
@Roles(['admin']) // 为当前路由设定权限角色
@UseGuards(RolesGuard) // 使用UseGuards为为当前路由绑定角色权限的守卫
将对应的数据打印出来即可一目了然
通过 this.reflector.get(Roles, context.getHandler());
获得绑定了 Roles 的路由函数,并获取到绑定的元数据,然后再用元数据和传入数据进行比较获得守卫的结果。
js
reflectors: {
Roles: {
createHello: {
metadata: ['admin']
}
}
}