Menu
CoddyTech

守卫

本课属于 Coddy Node.js 学习旅程的“TypeScript 和 NestJS”单元。第 18 课,共 24 课。

任何人都可以创建或删除任务。守卫会决定请求能否到达处理函数:Nest 会调用它的 canActivate,如果返回 false,Nest 会响应 403 禁止访问,而不会运行该方法。

@Injectable()
export class OpenHoursGuard implements CanActivate {
    canActivate(context: ExecutionContext): boolean {
        const hour = new Date().getHours();
        return hour >= 9 && hour < 17;
    }
}

@Post()
@UseGuards(OpenHoursGuard)
book() {}

context.switchToHttp().getRequest() 会返回请求;Node 会将请求头名称存为小写,因此要读取 request.headers['x-api-key']。方法上的 @UseGuards 会保护该方法。控制器类上的 @UseGuards 会保护其中的每个方法。

challenge icon

挑战

简单

目前,任何人都可以创建或删除任务。使用 API 密钥锁定这两个会更改数据的路由:客户端会在请求标头中发送这个密钥。所有人仍然可以读取数据。

  1. 打开 src/common/api-key.guard.ts。在 ApiKeyGuard 的 canActivate 方法中,读取请求的 x-api-key 标头。context.switchToHttp().getRequest() 会为你提供请求,标头名称始终是小写的。
  2. 只有当该标头的值等于 process.env.API_KEY 时才返回 true。本课将其设为 tasks-key-123。其他所有情况都返回 false,包括缺少标头的情况。当守卫返回 false 时,Nest 会响应 403,并且不会运行路由的方法。
  3. 在 src/tasks/tasks.controller.ts 中,从 ../common/api-key.guard 导入 ApiKeyGuard,并从 @nestjs/common 导入 UseGuards。在 create 方法(POST /tasks)和 remove 方法(DELETE /tasks/:id)上添加 @UseGuards(ApiKeyGuard)。不要把它加在类上,否则 GET 路由也会被锁定。
  4. GET /tasks、GET /tasks/:id 和 GET /stats 仍然可以在不提供密钥的情况下使用。

试试看:不添加标头,向 /tasks 发送 POST 请求,内容为 { "title": "Buy milk" }。你会收到 403:

{ "message": "Forbidden resource", "error": "Forbidden", "statusCode": 403 }

打开请求栏中的 Headers 字段,添加这一行 x-api-key: tasks-key-123,然后再次发送 POST 请求:你会收到 201 和新任务。使用 x-api-key: guess 时,你会收到 403。DELETE /tasks/4 也需要密钥:不提供密钥时返回 403,提供密钥时返回 204。完全不添加标头时,GET /tasks 也能正常使用。

亲手试试

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

@Injectable()
export class ApiKeyGuard implements CanActivate {
    canActivate(context: ExecutionContext): boolean {
        // 只有当请求的 x-api-key 请求头
        // 等于 process.env.API_KEY 时,才允许通过。
        return true;
    }
}
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

TypeScript 和 NestJS中的所有课

自己练习: Express 在线编辑器