如何用Guard保护NestJS中的ServeStaticModule模块?
实现方式
完全可以用NestJS原生风格实现,不需要在bootstrap()里直接挂载Express中间件,推荐两种方案:
方案一:自定义控制器接管受保护的静态文件路由(最贴合Nest风格)
1. 配置ServeStaticModule排除受保护路径
先在模块导入ServeStaticModule时,排除需要权限验证的静态文件路径,让自定义控制器接管这些路由:
import { Module } from '@nestjs/common'; import { ServeStaticModule } from '@nestjs/serve-static'; import { join } from 'path'; import { ProtectedStaticController } from './protected-static.controller'; @Module({ imports: [ ServeStaticModule.forRoot({ rootPath: join(__dirname, '..', 'public'), // 你的静态文件根目录 exclude: ['/protected*'], // 排除需要保护的路径前缀 }), ], controllers: [ProtectedStaticController], }) export class AppModule {}
2. 编写带Guard的控制器处理静态文件
创建控制器,挂载你已有的Guard,并手动处理静态文件的返回逻辑:
import { Controller, Get, Param, Res, UseGuards } from '@nestjs/common'; import { Response } from 'express'; import { join } from 'path'; import { YourExistingGuard } from './your-existing.guard'; // 导入你已有的守卫 @Controller('protected') @UseGuards(YourExistingGuard) // 应用你的守卫 export class ProtectedStaticController { @Get('*') getProtectedFile(@Param('0') filePath: string, @Res() res: Response) { // 拼接完整的静态文件路径 const fullFilePath = join(__dirname, '..', 'public', 'protected', filePath); // 返回静态文件 return res.sendFile(fullFilePath); } }
这种方式完全遵循Nest的路由、守卫机制,能直接复用你已有的Guard逻辑,不需要额外改造。
方案二:将Guard逻辑转为中间件注入ServeStaticModule
如果你不想额外编写控制器,可以把Guard的验证逻辑封装成Nest中间件,然后注入到ServeStaticModule的配置中:
1. 封装Guard逻辑为中间件
import { Injectable, NestMiddleware } from '@nestjs/common'; import { Request, Response, NextFunction } from 'express'; import { YourExistingGuard } from './your-existing.guard'; import { ExecutionContextHost } from '@nestjs/core/helpers/execution-context-host'; @Injectable() export class ProtectedStaticMiddleware implements NestMiddleware { constructor(private readonly guard: YourExistingGuard) {} async use(req: Request, res: Response, next: NextFunction) { // 构造适配Guard的ExecutionContext const context = new ExecutionContextHost([req, res]); const canActivate = await this.guard.canActivate(context); if (canActivate) { next(); } else { res.status(403).send('Forbidden'); } } }
2. 注入到ServeStaticModule
在模块中配置ServeStaticModule时,将中间件加入到serveStaticOptions的middleware数组:
ServeStaticModule.forRoot({ rootPath: join(__dirname, '..', 'public'), serveStaticOptions: { middleware: [ProtectedStaticMiddleware], }, })
不过这种方式需要手动适配Guard的ExecutionContext,不如方案一直接,所以更推荐方案一。
内容的提问来源于stack exchange,提问作者Konstantin Bodnia
相关产品推荐
相关产品推荐

