NestJS 9.4.2中如何用自定义装饰器验证私有HTTP请求权限?
实现NestJS私有HTTP请求验证(基于自定义装饰器与.env变量)
步骤1:配置环境变量与依赖
首先安装@nestjs/config来读取.env文件:
npm install @nestjs/config
在项目根目录的.env中添加验证密钥:
PRIVATE_API_KEY=your-secure-secret-key-here
然后在根模块中全局配置ConfigModule:
// src/app.module.ts import { Module } from '@nestjs/common'; import { ConfigModule } from '@nestjs/config'; import { AuthModule } from './auth/auth.module'; @Module({ imports: [ ConfigModule.forRoot({ isGlobal: true, // 全局注入,无需在子模块重复导入 }), AuthModule, ], }) export class AppModule {}
步骤2:创建私有接口守卫
守卫负责核心验证逻辑,对比请求中的密钥与.env配置值:
// src/common/guards/private.guard.ts import { Injectable, CanActivate, ExecutionContext, UnauthorizedException } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; import { Reflector } from '@nestjs/core'; // 自定义元数据键,用于标记私有接口 const IS_PRIVATE = 'isPrivate'; @Injectable() export class PrivateGuard implements CanActivate { constructor( private readonly configService: ConfigService, private readonly reflector: Reflector, ) {} canActivate(context: ExecutionContext): boolean { // 检查当前接口是否被标记为私有 const isPrivate = this.reflector.getAllAndOverride<boolean>(IS_PRIVATE, [ context.getHandler(), context.getClass(), ]); // 非私有接口直接放行 if (!isPrivate) return true; // 从请求Header中获取客户端提供的密钥 const request = context.switchToHttp().getRequest(); const providedKey = request.headers['x-api-key']; const validKey = this.configService.get<string>('PRIVATE_API_KEY'); // 验证密钥有效性 if (!providedKey || providedKey !== validKey) { throw new UnauthorizedException('无效或缺失API密钥'); } return true; } }
步骤3:创建自定义装饰器标记私有接口
用装饰器快速标记需要验证的接口:
// src/common/decorators/private.decorator.ts import { SetMetadata } from '@nestjs/common'; const IS_PRIVATE = 'isPrivate'; export const Private = () => SetMetadata(IS_PRIVATE, true);
步骤4:在控制器中应用验证逻辑
修改你的login接口,添加装饰器和守卫:
import { Controller, Post, Body, UseGuards } from '@nestjs/common'; import { Private } from '../common/decorators/private.decorator'; import { PrivateGuard } from '../common/guards/private.guard'; import { AuthDto } from './dto/auth.dto'; import { LoginService } from './login.service'; import { AuthService } from './auth.service'; import { BadRequestException } from '@nestjs/common'; @Controller('auth') export class AuthController { constructor( private readonly loginService: LoginService, private readonly authService: AuthService, ) {} @Post('/login') @Private() // 标记该接口为私有 @UseGuards(PrivateGuard) // 应用验证守卫 async login(@Body() body: AuthDto) { try { const usuario: IUser[] = await this.loginService.getUser(body); const tokens = await this.authService.getTokens(usuario); return tokens; } catch (error) { throw new BadRequestException('请求失败', { cause: error, description: '用户查询或令牌生成出错', }); } } }
验证逻辑说明
- 客户端请求时需在Header中携带
X-API-Key字段,值与.env中的PRIVATE_API_KEY一致 - 守卫会自动检查接口是否标记为私有,若未标记则直接放行;若标记则验证密钥有效性
- 密钥不匹配或缺失时返回
401 Unauthorized错误
内容的提问来源于stack exchange,提问作者francesco14
相关产品推荐
相关产品推荐

