Nestjs全网最佳翻译-概况-守卫-Guards
守卫
带上装饰器 @Injectable() 并实现了 CanActivate 接口的类,就是守卫。

守护只做一件事情。他们根据运行时的某些条件(如权限、角色、ACL等)来决定一个给定的请求是否会被路由处理程序处理。这通常被称为授权。在传统的Express应用程序中,授权、认证通常由中间件处理。中间件对于认证来说是一个很好的选择,因为像令牌验证和为请求对象附加属性这样的事情与特定的路由上下文(及其元数据)没有紧密联系。
但是,中间件存在天然缺陷。它不知道在调用next()函数后,哪个处理程序将被执行。另一方面,守卫可以访问 ExecutionContext 实例,因此知道下一步将执行什么。它们的设计很像异常过滤器、管道和拦截器,可以让你在请求/响应周期中的正确位置插入处理逻辑,而且是以声明的方式进行。
守护在所有中间件之后执行,但在任何拦截器或管道之前。
授权守卫
如前所述,授权是守卫的典型的使用案例,因为只有当调用者(通常是一个特定的认证用户)有足够的权限时,特定的路由才能使用。下面代码里面的 AuthGuard 假定有一个经过认证的用户(因此,在请求头文件中附有一个令牌)。它将提取并验证令牌,并使用提取的信息来确定请求是否可以继续。
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
import { Observable } from 'rxjs';@Injectable()
export class AuthGuard implements CanActivate {canActivate(context: ExecutionContext,): boolean | Promise<boolean> | Observable<boolean> {const request = context.switchToHttp().getRequest();return validateRequest(request);}
}
如果你正在寻找一个关于如何在你的应用程序中实现认证机制的真实案例,请访问本章。同样,对于更复杂的授权例子,请查看本页面。
validateRequest()函数内部的逻辑可以根据需要简单或复杂。这个例子的重点是展示守卫是如何融入请求/响应周期的。
每个守卫都必须实现一个canActivate()函数。这个函数应该返回一个布尔值,表明当前的请求是否被允许。它可以同步或异步地返回响应(通过Promise或Observable)。Nest使用返回值来控制下一个动作:
如果它返回true,该请求将被处理。
如果它返回false,Nest将拒绝该请求。
执行上下文
canActivate()函数需要一个参数,即ExecutionContext(执行上下文)实例。ExecutionContext 继承自 ArgumentsHost。我们之前在异常过滤器一章中看到了ArgumentsHost。在上面的例子中,我们只是使用了定义在ArgumentsHost上的相同的辅助方法,我们先前使用了这些方法,以获得对Request对象的引用。你可以参考异常过滤器一章中的Arguments host部分,了解更多关于这个主题的内容。
通过扩展ArgumentsHost,ExecutionContext还增加了几个新的辅助方法,提供关于当前执行过程的额外细节。这些细节有助于构建更多的通用守护,这些守护可以在广泛的控制器、方法和执行上下文中工作。在这里了解更多关于ExecutionContex的信息。
基于角色的认证
让我们建立一个功能更强的守卫,只允许具有特定角色的用户访问。我们将从一个基本的守卫开始,并在接下来的章节中对其进行构建。现在,它允许所有请求继续进行:
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;}
}
绑定守卫
像管道和异常过滤器一样,守护可以作用在控制器上,方法上,或者全局的。下面,我们使用@UseGuards()装饰器设置了一个控制器上的守卫。这个装饰器可以接受一个单独的参数,或者一个逗号分隔的参数列表。这让你可以通过一个声明轻松地应用适当的守卫集。
@Controller('cats')
@UseGuards(RolesGuard)
export class CatsController {}
@UseGuards() 装饰器是从 @nestjs/common 包中导入的。
上面,我们传递了RolesGuard类(而不是一个实例),将实例化的责任留给了框架,并实现了依赖性注入。与管道和异常过滤器一样,我们也可以传递一个新的实例:
@Controller('cats')
@UseGuards(new RolesGuard())
export class CatsController {}
上面的代码处理的时候会将守卫附加到这个控制器所声明的每个处理程序上。如果我们希望守卫只适用于一个方法,我们可以在方法层应用@UseGuards() 装饰器。
为了设置全局守卫,使用Nest应用程序实例的useGlobalGuards()方法:
const app = await NestFactory.create(AppModule);
app.useGlobalGuards(new RolesGuard());
对于混合型应用程序,useGlobalGuards()方法默认不为网关和微服务设置守卫(关于如何改变这一行为的信息,请参见混合型应用程序)。对于 “标准”(非混合型)微服务应用程序,useGlobalGuards()确实在全局范围内安装防护。(译者注:这里和pipes里面的一样的)
全局守卫在整个应用程序中会作用在每个控制器和每个路由处理程序。在依赖注入方面,从任何模块之外注册的全局守卫(如上面的例子中使用useGlobalGuards())不能注入依赖,因为这是在任何模块的上下文之外进行的。为了解决这个问题,你可以使用下面的方式直接从任何模块中设置一个守卫:(译者注:就是上面直接在app注册的守卫,module是引用不到的)
import { Module } from '@nestjs/common';
import { APP_GUARD } from '@nestjs/core';@Module({providers: [{provide: APP_GUARD,useClass: RolesGuard,},],
})
export class AppModule {}
当使用这种方法为守卫进行依赖性注入时,请注意,无论在哪个模块采用这种方式,守卫实际上都是全局性的。这应该在哪里进行呢?选择定义了防护(上面例子中的RolesGuard)的模块。另外,useClass并不是处理自定义提供者注册的唯一方法。在这里了解更多。
我们的RolesGuard可以工作了,但是它还不够聪明。我们还没有利用最重要的守卫特性–执行上下文。它还不知道角色,或者每个处理程序允许哪些角色。例如,CatsController可以为不同的路线提供不同的权限方案。有些可能只对管理员用户开放,而有些可能对所有人开放。我们怎样才能以一种灵活和可重用的方式将角色与路由相匹配呢?
这就是自定义元数据发挥作用的地方(在这里了解更多)。Nest提供了通过@SetMetadata()装饰器将自定义元数据附加到路由处理程序的能力。这个元数据提供了我们缺失的角色数据,智能守卫需要这些数据来做出决定。让我们来看看如何使用@SetMetadata():
@Post()
@SetMetadata('roles', ['admin'])
async create(@Body() createCatDto: CreateCatDto) {this.catsService.create(createCatDto);
}
@SetMetadata()装饰器是从@nestjs/common包中导入的。
通过上面的结构,我们将角色元数据(角色是一个key,而[‘admin’]是一个特定的value)附加到create()方法中。虽然这很有效,但在你的路由中直接使用@SetMetadata()并不是好的做法。相反,创建你自己的装饰器,如下所示:
import { SetMetadata } from '@nestjs/common';
export const Roles = (...roles: string[]) => SetMetadata('roles', roles);
这种方法更简洁、更易读,而且是强类型的。现在我们有一个自定义的@Roles()装饰器,我们可以用它来装饰create()方法。
@Post()
@Roles('admin')
async create(@Body() createCatDto: CreateCatDto) {this.catsService.create(createCatDto);
}
完善RolesGuard
现在让我们把 RolesGuard 功能完善起来。目前,它在所有情况下都简单地返回true,允许每个请求继续进行。我们想在比较分配给当前用户的角色和当前正在处理的路由所要求的实际角色的基础上,使返回值成为条件。为了访问路由的角色(自定义元数据),我们将使用Reflector帮助类,它是由框架提供的,并可以从@nestjs/core包中导入。
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);}
}
在node.js世界中,通常的做法是将授权用户附加到请求对象中。因此,在我们上面的示例代码中,我们假设 request.user 包含用户实例和允许的角色。在你的应用程序中,你可能会在你的自定义认证防护(或中间件)中进行这种关联。请查看本章以了解有关这一主题的更多信息。
matchRoles()函数内部的逻辑可以根据需要简单或复杂。这个例子的重点是展示守卫如何融入请求/响应周期。
请参考执行上下文章节的反射和元数据部分,了解以上下文敏感的方式利用反射器的更多细节。
当权限不足的用户请求一个端点时,Nest自动返回以下响应:
{"statusCode": 403,"message": "Forbidden resource","error": "Forbidden"
}
请注意,当一个守卫返回错误时,Nestjs框架会抛出一个ForbiddenException。如果你想返回一个不同的错误响应,你应该抛出你自己的特定异常。比如说:
throw new UnauthorizedException();
由守卫装置抛出的任何异常将由异常层(全局异常过滤器和应用于当前上下文的任何异常过滤器)处理。
如果你正在寻找一个关于如何实现授权的真实例子,请查看本章。
总结
本章节主要内容如下:
守卫的主要职责。
守卫的重要特性ExecutionContext(执行上下文)。
守卫的作用范围。
如何建立基于角色的守卫。
利用装饰器封装守卫。
注意本章节代码只是演示代码,文中有具体例子的链接。
相关文章:
Nestjs全网最佳翻译-概况-守卫-Guards
守卫 带上装饰器 Injectable() 并实现了 CanActivate 接口的类,就是守卫。 守护只做一件事情。他们根据运行时的某些条件(如权限、角色、ACL等)来决定一个给定的请求是否会被路由处理程序处理。这通常被称为授权。在传统的Express应用程序中…...
【软考网络管理员】2023年软考网管初级常见知识考点(3)- 网络体系结构
【写在前面】也是趁着五一假期前再写几篇分享类的文章给大家,希望看到我文章能给软考网络管理员备考的您带来一些帮助,5月27号也是全国计算机软件考试统一时间,也就不用去各个地方找资料和代码了。紧接着我就把我整理的一些资料分享给大家哈&…...
javascript正则表达式大括号、中括号、小括号的作用以及应用场景
在JavaScript正则表达式中,大括号 {}、中括号 [] 和小括号 () 都有不同的作用和应用场景。 大括号 {} 在正则表达式中,大括号 {} 表示重复次数。以下是一些常见的应用场景: {n}:精确匹配出现的次数,例如 \d{3} 匹配…...
5年测试老鸟总结,自动化测试的实施到落地,看这一篇足够...
目录:导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结(尾部小惊喜) 前言 Python自动化测试&…...
通达信顾比倒数线指标公式,信号不漂移
顾比倒数线是由技术派大师戴若顾比发明的,该指标利用三个重要的价格来判断入场或离场时机,可用于盘后制定下一个交易日的操作计划。此外,顾比倒数线还可以用于补充验证其他指标。 在编写顾比倒数线选股公式之前,需要先了解顾比倒…...
网络安全: CIDR无类别路由
网络安全: CIDR无类别路由 CIDR是无类别路由,出现CIDR的原因是因为ipv4的地址被使用完客,CIDR的出现暂缓了ipv4用完的速度。 原本的ipv4很刻板,网络号分成8位,16位,24位作为掩码,也就是 xxx.0…...
NetMQ | 发布订阅时使用含通配符的Topic
NetMQ | 发布订阅时使用含通配符的Topic 文章目录 NetMQ | 发布订阅时使用含通配符的Topic前言通配符如何使用通配符通配符的作用结束语 前言 今天我来介绍一下NetMQ发布订阅时如何使用含通配符的Topic,让我们能够更加灵活地订阅消息。 什么是Topic? 在NetMQ中&am…...
行为型模式-模板方法模式
模板方法模式 概述 在面向对象程序设计过程中,程序员常常会遇到这种情况:设计一个系统时知道了算法所需的关键步骤,而且确定了这些步骤的执行顺序,但某些步骤的具体实现还未知,或者说某些步骤的实现与具体的环境相关…...
IPsec中IKE与ISAKMP过程分析(快速模式-消息1)
IPsec中IKE与ISAKMP过程分析(主模式-消息1)_搞搞搞高傲的博客-CSDN博客 IPsec中IKE与ISAKMP过程分析(主模式-消息2)_搞搞搞高傲的博客-CSDN博客 IPsec中IKE与ISAKMP过程分析(主模式-消息3)_搞搞搞高傲的博客…...
PostgreSQL 数据类型转换
各种数据类型(日期/时间、integer、floating point和numeric)转换成格式化的字符串及反过来从格式化的字符串转换成指定的数据类型,在实际操作中经常遇到。下面总结了一些常用的函数。 日期操作函数 函数返回类型描述实例to_char(timestamp…...
【Java笔试强训 1】
🎉🎉🎉点进来你就是我的人了博主主页:🙈🙈🙈戳一戳,欢迎大佬指点! 欢迎志同道合的朋友一起加油喔🦾🦾🦾 目录 一、选择题 二、编程题 🔥组队竞…...
你买票了吗?五一火车票发售量创历史新高,车票总发售2209万张票
五一劳动节已经成为了除春节国庆节外最隆重的节日,是全国性的庆祝节日。在这个节日里,人们可以通过旅游、购物、娱乐等方式来放松身心,充满活力地迎接新的挑战。同时,五一假期也成为了国内外客流量最大的旅游黄金周之一࿰…...
DiffUtil的使用
RecyclerView的DiffUtil用于计算并更新RecyclerView中数据集的变化。通过使用DiffUtil,我们可以避免完全重新加载整个列表,并且只会更改必要的视图。 以下是DiffUtil的基本用法: 创建一个继承自DiffUtil.Callback的类来计算差异。在这个类中…...
【Python】【进阶篇】18、Django初始化项目环境精讲
目录 18、Django初始化项目环境精讲1. 完成数据库迁移2. PyMySQL模块的使用3. migrate与makemigrations命令详解1) makegrations生成数据库迁移文件2) migrate执行数据库迁移命令3) 完成数据库迁移总结 18、Django初始化项目环境精讲 上一节中,我们完成了对 settin…...
Web前端基础
一.说明 如果你要了解web前端领域,那么三种语言是你必须要了解的,即html5、CSS、Javascript是你必须要了解的,通过前面的专栏内容你一定对html标记语言非常熟悉,那么其他两种语言是什么,他们怎么和html联系在一起&…...
ACM 1007 | 分段函数求值
文章目录 0x00 前言 0x01 题目描述 0x02 问题分析 0x03 代码设计 0x04 完整代码 0x05 运行效果 0x06 总结 0x00 前言 C 语言网不仅提供 C 语言,还包括 C 、 java 、算法与数据结构等课程在内的各种入门教程、视频录像、编程经验、编译器教程及软件下载、题解博…...
ChatGPT技术原理 第十四章:未来发展方向
目录 14.1 多模态对话生成 14.2 跨语言对话生成 14.3 增量学习 14.4 深度强化学习...
大型水利投资集团,打造数智财资管理新范式
随着我国城市化进程的不断推进,城市基础设施在国民经济中的作用愈加重要,其建设水平直接影响一个城市的竞争力。国有城投、水投等企业作为城市基础设施建设的主要参与者,其重要性不言而喻。随着国家、地方对基础设施重要性认识的加深以及政府…...
【java】彻底剖析 Synchronized
文章目录 前言对象结构Monitor 对象Synchronized特征原子性可见性有序性可重入锁 锁升级的过程 前言 源码级别剖析Synchronized 对象结构 Synchronized是Java中的隐式锁,它的获取锁和释放锁都是隐式的,完全交由JVM帮助我们操作,在了解Sync…...
有反爬机制就爬不了吗?那是你还不知道反反爬,道高一尺魔高一丈啊
文章目录 一、从用户请求的Headers反爬虫二、基于用户行为反爬虫(1)方法1(2)方法2 三、动态页面的反爬虫四.总结 不知道你们在用爬虫爬数据的时候是否有发现,越来越多的网站都有自己的反爬机制,抓取数据已经…...
Vue记事本应用实现教程
文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展:显示创建时间8. 功能扩展:记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...
地震勘探——干扰波识别、井中地震时距曲线特点
目录 干扰波识别反射波地震勘探的干扰波 井中地震时距曲线特点 干扰波识别 有效波:可以用来解决所提出的地质任务的波;干扰波:所有妨碍辨认、追踪有效波的其他波。 地震勘探中,有效波和干扰波是相对的。例如,在反射波…...
云计算——弹性云计算器(ECS)
弹性云服务器:ECS 概述 云计算重构了ICT系统,云计算平台厂商推出使得厂家能够主要关注应用管理而非平台管理的云平台,包含如下主要概念。 ECS(Elastic Cloud Server):即弹性云服务器,是云计算…...
最新SpringBoot+SpringCloud+Nacos微服务框架分享
文章目录 前言一、服务规划二、架构核心1.cloud的pom2.gateway的异常handler3.gateway的filter4、admin的pom5、admin的登录核心 三、code-helper分享总结 前言 最近有个活蛮赶的,根据Excel列的需求预估的工时直接打骨折,不要问我为什么,主要…...
vue3 字体颜色设置的多种方式
在Vue 3中设置字体颜色可以通过多种方式实现,这取决于你是想在组件内部直接设置,还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法: 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...
Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器
第一章 引言:语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域,文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量,支撑着搜索引擎、推荐系统、…...
论文浅尝 | 基于判别指令微调生成式大语言模型的知识图谱补全方法(ISWC2024)
笔记整理:刘治强,浙江大学硕士生,研究方向为知识图谱表示学习,大语言模型 论文链接:http://arxiv.org/abs/2407.16127 发表会议:ISWC 2024 1. 动机 传统的知识图谱补全(KGC)模型通过…...
Unity | AmplifyShaderEditor插件基础(第七集:平面波动shader)
目录 一、👋🏻前言 二、😈sinx波动的基本原理 三、😈波动起来 1.sinx节点介绍 2.vertexPosition 3.集成Vector3 a.节点Append b.连起来 4.波动起来 a.波动的原理 b.时间节点 c.sinx的处理 四、🌊波动优化…...
稳定币的深度剖析与展望
一、引言 在当今数字化浪潮席卷全球的时代,加密货币作为一种新兴的金融现象,正以前所未有的速度改变着我们对传统货币和金融体系的认知。然而,加密货币市场的高度波动性却成为了其广泛应用和普及的一大障碍。在这样的背景下,稳定…...
使用Spring AI和MCP协议构建图片搜索服务
目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式(本地调用) SSE模式(远程调用) 4. 注册工具提…...
