nest 守卫

时间:2023-01-07 浏览:169 分类:NestJS

作用

功能:守卫有单一的责任,它们根据运行时存在的某些条件(如权限、角色、ACL 等)确定给定请求是否将由路由处理程序处理,这通常称为授权。

在传统的 Express 应用程序中,授权(及其表亲,身份验证,通常与之协作)通常由中间件处理。中间件是身份验证的不错选择,因为诸如令牌验证和将属性附加到请求对象之类的事情与特定路由上下文(及其元数据)没有紧密联系。但是中间件,就其本质而言,是木讷的。它不知道调用 next() 函数后将执行哪个处理程序。另一方面,守卫可以访问 ExecutionContext 实例,因此确切地知道接下来要执行什么。它们的设计与异常过滤器、管道和拦截器非常相似,可让您在请求/响应周期的正确位置插入处理逻辑,并以声明方式进行。这有助于使您的代码保持干爽和声明式。

守卫在所有中间件之后执行,但在任何拦截器或管道之前执行。

使用方法

第一步:自定义守卫逻辑 可以 nest g guard user 创建守卫

// user.guard.ts

import {CanActivate, ExecutionContext, Injectable} from '@nestjs/common';
import {Observable} from 'rxjs';

@Injectable()
export class UserGuard implements CanActivate {
    canActivate(
        context: ExecutionContext,
    ): boolean | Promise<boolean> | Observable<boolean> {
        const request = context.switchToHttp().getRequest();
        const response = context.switchToHttp().getResponse();
        let query = request.query;
        if (query.id === '1') {
            return true;    // 返回true 才能继续执行,返回false 或者其他将终止请求
        } else {
            return response.redirect('/404');
        }
    }
}

第二步:引用守卫 UseGuards

// user.controller.ts

import {UserGuard} from "./user.guard";
import {UseGuards} from "@nestjs/common";

@Controller('user')
@UseGuards(UserGuard).  //在这里使用装饰器引入
export class UserController {
    constructor(private readonly userService: UserService) {
    }
    
    @Get('/test')
    test(@Query() query) {
        console.log(query);
        return 'test'
    }
}

全局引入

方法一:

// main.ts

const app = await NestFactory.create(AppModule);
app.useGlobalGuards(new RolesGuard());

方法二:

// app.module.ts

import { Module } from '@nestjs/common';
import { APP_GUARD } from '@nestjs/core';

@Module({
  providers: [
    {
      provide: APP_GUARD,
      useClass: RolesGuard,
    },
  ],
})
export class AppModule {}

如果在守卫中需要排除检测某一项路由,可以在定义守卫时加上判断url 路径的逻辑,如下:

import {CanActivate, ExecutionContext, Injectable} 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();
        const response = context.switchToHttp().getResponse();
        let query = request.query;
        // 被排除的路由,如果匹配则不检测guard
        const excludeRoutes = [
            '/user',
            '/user/test',
        ];
        if (excludeRoutes.includes(request.path)) {
            return true;
        }
        if (query.id === '1') {
            return true;
        } else {
            return response.redirect('/404');
        }
    }
}