守卫
本课属于 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 会保护其中的每个方法。
挑战
简单目前,任何人都可以创建或删除任务。使用 API 密钥锁定这两个会更改数据的路由:客户端会在请求标头中发送这个密钥。所有人仍然可以读取数据。
- 打开
src/common/api-key.guard.ts。在ApiKeyGuard的canActivate方法中,读取请求的x-api-key标头。context.switchToHttp().getRequest()会为你提供请求,标头名称始终是小写的。 - 只有当该标头的值等于
process.env.API_KEY时才返回true。本课将其设为tasks-key-123。其他所有情况都返回false,包括缺少标头的情况。当守卫返回false时,Nest 会响应 403,并且不会运行路由的方法。 - 在
src/tasks/tasks.controller.ts中,从../common/api-key.guard导入ApiKeyGuard,并从@nestjs/common导入UseGuards。在create方法(POST /tasks)和remove方法(DELETE /tasks/:id)上添加@UseGuards(ApiKeyGuard)。不要把它加在类上,否则 GET 路由也会被锁定。 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;
}
}
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
TypeScript 和 NestJS中的所有课
自己练习: Express 在线编辑器