Nestjs全网最佳翻译-概况-守卫-Guards

news2024/11/25 22:53:26

守卫

带上装饰器 @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(执行上下文)。

守卫的作用范围。

如何建立基于角色的守卫。

利用装饰器封装守卫。

注意本章节代码只是演示代码,文中有具体例子的链接。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/471867.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

浅析AI视频智能检测技术在城市管理中的场景应用

随着中国的城市建设和发展日益加快&#xff0c;城镇化过程中重建设、轻管理模式带来不少管理难点&#xff0c;传统城管模式存在违法问题多样、缺乏源头治理、业务协同难、取证手段单一等&#xff0c;人员不足问题进一步加剧管理难度。随着移动互联网、物联网、云计算、大数据、…

Vue3 全局实例上挂载属性方法

导语 在大多数开发需求中&#xff0c;我们有时需要将某个数据&#xff0c;或者某个函数方法&#xff0c;挂载到&#xff0c;全局实例身上&#xff0c;以便于&#xff0c;在项目全局的任何位置都能够调用其方法&#xff0c;或读取其数据。 在Vue2 中&#xff0c;我们是在 main.j…

【Unity URP】Rendering Debugger和可视化MipMap方案

写在前面 最近开始学习Unity性能优化&#xff0c;是结合了《Unity游戏优化》这本书和教程《Unity性能优化》第叁节——静态资源优化(3)——纹理的基础概念一起学习。在学习纹理优化部分时候遇到了问题&#xff0c;固定管线下Unity的Scene窗口有一个可视化Mipmap的渲染模式&…

ChatGPT实现数据结构转换

数据结构转换 在应用系统开发和维护中&#xff0c;经常会有配置数据或客户数据需要在不同的序列化结构中相互转换的需求。不同编程语言之前&#xff0c;对数据结构的偏好也不一样&#xff0c;比如 JavaScript 一般使用 JSON、Java 一般使用 XML、Ruby 一般使用 YAML、Golang 一…

搞懂 API , API 这些特点要记住

API 是现代软件开发和应用程序中的必要组成部分&#xff0c;它为企业和开发者提供了极大的便利和工作效率。不过&#xff0c;API 也有其不足之处。下面将在这篇文章中详细探讨 API 的优点和缺点。 优点&#xff1a; 简化数据访问和交互 API 消除了传统的数据集成方法&#x…

使用chatGPT开发获取格点天气数据

1. 格点天气 1.1. 格点天气 以经纬度为基准的全球高精度、公里级、格点化天气预报产品&#xff0c;包括任意经纬度的实时天气和天气预报。其中&#xff0c;任意坐标的高精度天气&#xff0c;精确到3-5公里范围&#xff0c;包括&#xff1a;温度、湿度、大气压、天气状况、风力…

nvidia-smi命令解析

桌面端 服务器端 Fan:风扇转速&#xff08;0%-100%&#xff09;&#xff0c;N/A表示没有风扇 Temp&#xff1a;GPU温度&#xff08;GPU温度过高会导致GPU频率下降&#xff09; Perf&#xff1a;性能状态&#xff0c;从P0&#xff08;最大性能&#xff09;到P12&#xff08;最…

zookeeper 安装下载与集群

一、单机部署 1、安装包下载 https://archive.apache.org/dist/zookeeper 2、上传并解压 tar -zvxf zookeeper-3.4.14.tar.gz3、配置环境变量 my_env.sh是自己创建的环境变量文件&#xff0c;你也可以自己创建 vim /etc/profile.d/my_env.sh#ZOOKEEPER_HOME export ZOOKE…

什么是分布式任务调度?怎样实现任务调度

通常任务调度的程序是集成在应用中的&#xff0c;比如&#xff1a;优惠卷服务中包括了定时发放优惠卷的的调度程序&#xff0c;结算服务中包括了定期生成报表的任务调度程序&#xff0c;由于采用分布式架构&#xff0c;一个服务往往会部署多个冗余实例来运行我们的业务&#xf…

1.3 防火墙通过TELNET登录设备

防火墙通过TELNET登录设备 需求&#xff1a;使远程管理员能够通过telnet方式登录到设备上进行管理 序号任务任务说明备注1物理连接略2登录设备略3配置设备telnet设备默认不支持telnet功能&#xff0c;必须开启telnet功能&#xff0c;以及用于远程登录设备的账号密码等。重点4测…

【hello Linux】进程间通信——共享内存

目录 前言&#xff1a; 1. System V共享内存 1. 共享内存的理解 2. 共享内存的使用步骤 3. 共享内存的使用 1. 共享内存的创建 查看共享内存 2. 共享内存的释放 3. 共享内存的挂接 4. 共享内存的去挂接 4. 共享内存的使用示例 1. 两进程挂接与去挂接演示&#xff1a; 2. 两进程…

基于eNSP的IPv4加IPv6的企业/校园网络规划设计(综合实验/大作业)

作者&#xff1a;BSXY_19计科_陈永跃 BSXY_信息学院_名片v位于结尾处 注&#xff1a;未经允许禁止转发任何内容 基于eNSP的IPv4加IPv6的企业/校园网络规划设计_综合实验/大作业 前言及技术/资源下载说明&#xff08; **未经允许禁止转发任何内容** &#xff09;一、设计topo图与…

Postgresql逻辑优化学习

张树杰优化器原理学习 0 用例 drop table student; create table student(sno int primary key, sname varchar(10), ssex int); insert into student values(1, stu1, 0); insert into student values(2, stu2, 1); insert into student values(3, stu3, 1); insert into stu…

SPSS岭回归报错问题 第 8 列中的 错误号 34+乱码问题

1首先第一个问题&#xff0c;先找到Ridge Regression.sps文件 注意各国语言都有这个文件&#xff0c;选择English下的 得到位置&#xff0c;一般是安装路径\Samples\English\Ridge Regression.sps 仍然报错&#xff0c;将第二行变成大写&#xff1a;RIDGEREG ENTER&#xff0…

笔记本电脑没有声音了怎么恢复

笔记本电脑 在使用的过程中&#xff0c;突然没有声音的话&#xff0c;对于人们来说会很麻烦。那么笔记本电脑没有声音了怎么恢复呢?下面小编为大家整理了笔记本电脑没有声音的恢复方法&#xff0c;一起来看看吧。 方法/步骤&#xff1a; 方法一&#xff1a;网络适配器检查音频…

物联网工程有哪些SCI期刊推荐? - 易智编译EaseEditing

以下是一些物联网工程领域的SCI期刊推荐&#xff1a; IEEE Internet of Things Journal&#xff1a; 该期刊由IEEE出版&#xff0c;致力于物联网技术领域的研究&#xff0c;包括物联网的基础理论、通信、算法、应用、系统等方面。 Sensors&#xff1a; 该期刊由MDPI出版&…

基于el-input的数字范围输入框

数字范围组件 在做筛选时可能会出现数字范围的筛选&#xff0c;例如&#xff1a;价格、面积&#xff0c;但是elementUI本身没有自带的数字范围组件&#xff0c;于是进行了简单的封装&#xff0c;不足可自行进行优化 满足功能&#xff1a; 最小值与最大值的相关约束&#xff0…

C++默认成员函数 日期类运算符重载

赋值重载 赋值重载&#xff0c;首先我们先说一个运算符重载&#xff0c;什么是运算符重载呢&#xff1f; 当我们有一个日期类的话&#xff0c;我们想要对&#xff0c; 一个日期类进行比较&#xff0c;那么我们怎么比较呢&#xff1f; 我们是不是先得比较年的大小&#xff0c;…

day6 socket套接字及TCP的实现框架

socket套接字 Berkeley UNIX 操作系统定义了一种API它又称为套接字接口&#xff08;socket interface); socket作用&#xff1a; socket常见API介绍 /*创建套接字*/ int socket(int domain, int type, int protocol); /*绑定通信结构体*/ int bind(int sockfd, const, struc…

【数据库】MVCC原理详解

文章目录 前言1. 相关数据库知识点回顾1.1 什么是数据库事务&#xff0c;为什么要有事务1.2 事务包括哪几个特性&#xff1f;1.3 事务并发存在的问题1.3.1 脏读1.3.2 不可重复读1.3.3 幻读 1.4 四大隔离级别1.4.1 读未提交1.4.2 读已提交1.4 3 可重复读1.4.4 串行化1.4.5 四大隔…