一篇文章学会如何使用 NestJS 的 Guards 守卫实现系统身份验证和授权

前言

当我们基于NestJS框架构建和管理应用程序时,为了保障其安全性,我们常常需要对某些敏感操作或敏感信息的访问进行限制,这是我们需要使用到 守卫 的地方。它作为一种可以阻止未经授权的访问的机制,对我们的应用程序起到了守护的作用。

在这篇文章中,我将深入剖析 NestJS 的守卫,以帮您全面了解这个概念。我会从解释其背后的工作机制开始,接着介绍使用守卫的各种场景,并以详细的示例来演示如何在 NestJS 项目中实现和使用守卫。

什么是 Guards 守卫

在去解析NestJS的守卫之前,我们先来简单了解一下NestJS。NestJS是一种设计用于构建高效,可扩展的 Node.js 服务器端应用程序的框架。它使用渐进式 JavaScript,内置并完全支持 TypeScript,并结合了 OOP、FP 和 FRP 的元素。

既然我们已经对NestJS有了基本的理解,那么,什么是NestJS的守卫(Guards)呢?简单来说,守卫(Guards)是NestJS中的一个概念,其职责就像其名字一样,它起到了保护我们应用程序不被未经授权的访问的作用。在特定的路由处理程序执行之前,守卫负责确定请求是否应该被路由处理程序处理。

使用场景

守卫通常用于身份验证和授权,也就是在执行业务代码之前验证用户是否有权做出某个操作。

例如,在许多应用程序中,你需要防止未经授权的用户访问敏感信息或执行特定的操作。若用户请求查看或修改某些只有特定权限或角色才能查看或修改的数据时,守卫即可起到“守门人”的作用。

使用案例

一、创建一个身份验证守卫

我们首先要创建一个 AuthGuard 类并注入它。这个类需要实现 CanActivate 接口并实现 canActivate 方法:

typescript
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(); // 添加你的身份验证逻辑 // For example: return validateRequest(request); } }

在上面的示例中,我们首先从 @nestjs/common 包导入了 InjectableCanActivate 和 ExecutionContext。然后,我们创建了一个 AuthGuard 类,它会实现 CanActivate 接口,这个接口要求我们实现 canActivate 方法。

在这个方法中,我们首先获取上下文请求对象。然后,我们可以在这个方法中执行我们需要的任何判断逻辑,比如检查请求中是否包含有效的 JWT 令牌。

二、使用身份验证守卫(控制器维度)

现在,我们已经创建了守卫,那该如何使用呢?其实非常简单,我们只需要在控制器或者具体路由上添加 @UseGuards() 装饰器:

typescript
import { Controller, Get, UseGuards } from '@nestjs/common'; import { AuthGuard } from './auth.guard'; @Controller('users') @UseGuards(AuthGuard) export class UserController { @Get() findAll() { return "这个操作返回所有的猫,只有通过身份验证的用户能看到!"; } }

这样,我们就可以确保只有通过 AuthGuard 权限认证的用户才能够访问到我们的 CatsController 控制器中的所有路由。

三、使用身份验证守卫(路由维度)

如果你只希望在某个特定的路由上应用这个守卫,而不是整个控制器,你可以将 UseGuards 装饰器应用于具体的路由处理函数:

typescript
import { Controller, Get, UseGuards } from '@nestjs/common'; import { AuthGuard } from './auth.guard'; @Controller('cats') export class CatsController { @Get() @UseGuards(AuthGuard) findOne() { return "这个操作返回一只猫,只有通过身份验证的用户能看到!"; } }

总结

以上我们已经展示了如何创建和使用自定义守卫。然而,在真实的业务场景中,可能会有更复杂的情况,比如基于角色的访问控制(Role-Based Access Control, RBAC)。这种情况下,你的守卫可能需要复杂的逻辑来确定一个用户能接触哪些资源。这些都是你可以使用守卫来处理的场景。

总的来说,NestJS 的守卫是一个非常强大的工具,特别是对于大型和复杂的项目,在权限判断上,使用守卫可以极大地提高代码的可维护性和安全性。