如何在NestJS混入类(Mixin)守卫中注入PrismaService?
解决NestJS带参数守卫中注入PrismaService的问题
方法一:为动态混入类添加@Injectable()装饰器
这是最直接的解决方案,通过给动态生成的守卫类添加@Injectable()装饰器,让Nest的依赖注入容器识别并管理这个类,从而自动注入PrismaService。
修改后的完整代码:
import { Injectable, mixin, CanActivate, ExecutionContext } from '@nestjs/common'; import { PrismaService } from './prisma.service'; // 替换为你的PrismaService实际路径 export const UserGuard = (table: Prisma.ModelName, field: string) => { @Injectable() class RoleGuardMixin implements CanActivate { // 通过构造函数注入PrismaService,并使用private readonly确保可访问 constructor(private readonly prismaService: PrismaService) {} async canActivate(context: ExecutionContext) { // 示例逻辑:从请求中获取用户ID,查询对应表的记录 const request = context.switchToHttp().getRequest(); const userId = request.user.id; // 假设请求对象中携带用户信息 const subject = await this.prismaService[table].findUnique({ where: { [field]: userId }, }); // 根据查询结果返回权限验证结果,这里示例为存在则通过 return !!subject; } } return mixin(RoleGuardMixin); };
关键说明
@Injectable()是核心:它标记动态类为Nest DI容器的管理对象,确保PrismaService能被自动注入。- 构造函数中必须使用
private readonly:否则this.prismaService无法在canActivate方法中访问。
方法二:使用ModuleRef手动获取服务
如果某些场景下自动注入不生效,可以通过ModuleRef手动从DI容器中获取PrismaService,适合更复杂的动态场景。
代码示例:
import { Injectable, mixin, CanActivate, ExecutionContext, ModuleRef } from '@nestjs/common'; import { PrismaService } from './prisma.service'; export const UserGuard = (table: Prisma.ModelName, field: string) => { @Injectable() class RoleGuardMixin implements CanActivate { private readonly prismaService: PrismaService; constructor(private readonly moduleRef: ModuleRef) { // 从模块引用中获取PrismaService,strict: false允许获取全局注册的服务 this.prismaService = moduleRef.get(PrismaService, { strict: false }); } async canActivate(context: ExecutionContext) { const request = context.switchToHttp().getRequest(); const userId = request.user.id; const subject = await this.prismaService[table].findUnique({ where: { [field]: userId }, }); return !!subject; } } return mixin(RoleGuardMixin); };
使用方式
在控制器中直接调用带参数的守卫工厂函数即可:
import { Controller, Get, UseGuards } from '@nestjs/common'; import { UserGuard } from './user.guard'; @Controller('users') export class UsersController { @UseGuards(UserGuard('User', 'id')) @Get() async getCurrentUser() { // 控制器逻辑 } }
前置条件
确保PrismaService已正确注册:
- 要么在
PrismaModule上添加@Global()装饰器,使其成为全局服务; - 要么在使用守卫的模块中导入
PrismaModule。
内容的提问来源于stack exchange,提问作者Tevon Strand-Brown
相关产品推荐
相关产品推荐

