在 Nest.JS 中将服务注入警卫
Posted
技术标签:
【中文标题】在 Nest.JS 中将服务注入警卫【英文标题】:Inject service into guard in Nest.JS 【发布时间】:2019-03-22 14:11:32 【问题描述】:我有 KeysModule,可用于添加或删除 API 密钥。我需要这些密钥来保护某些路由免受未经授权的访问。 为了保护这些路由,我创建了 ApiGuard:
import CanActivate, ExecutionContext, Injectable from '@nestjs/common';
@Injectable()
export class ApiGuard implements CanActivate
async canActivate(
context: ExecutionContext,
): Promise<boolean>
const request = context.switchToHttp().getRequest();
return request.headers.api_key;
然后我在路由中使用它:
@Get('/protected')
@UseGuards(ApiGuard)
async protected(@Headers() headers: Api)
const key = await this.ks.findKey( key: headers.api_key );
if (!key || !key.active) return 'Invalid Key';
return 'Your API key works';
其中 ks 是用于检查密钥是否正确的 KeyService。 这个解决方案有效,但很愚蠢。我必须在任何我想使用这个守卫的地方复制和粘贴一些代码行(我的意思是路线中的行)。
我尝试将所有逻辑移至 ApiGuard,但出现错误,无法将 KeyService 注入 ApiGuard 类。说明一下,我在 KeysModule 的 provider 中有 KeyService,但是 ApiGuard 是全局使用的。
你知道怎么做吗?
【问题讨论】:
【参考方案1】:从 NestJS v8 开始,似乎在接受的答案中注入 zsoca 回答的服务不再起作用。
NestJS 8 的有效解决方案是提供类引用而不是字符串:
constructor(@Inject(KeyService) private keyService: KeyService)
【讨论】:
【参考方案2】:守卫中使用的服务必须在其模块中导出。提供服务还不够!
【讨论】:
【参考方案3】:在guard中注入服务。你可以创建一个全局模块。
// ApiModule
import Module,Global from '@nestjs/common';
import KeyService from '../';
@Global()
@Module(
providers: [ KeyService ],
exports: [KeyService]
)
export class ApiModule
然后像这样将服务注入到守卫中
// guard
export class ApiGuard implements CanActivate
constructor(@Inject('KeyService') private readonly KeyService)
async canActivate(context: ExecutionContext)
// your code
throw new ForbiddenException();
现在问题可以解决了。但是我还有一个问题。我想向服务中注入一些东西但是得到了这个错误:
Nest 无法解析 AuthGuard (?, +) 的依赖关系。请确保索引 [0] 处的参数在当前上下文中可用。
这是我的解决方案:
在 KeyService 中注入其他依赖,比如nestjs docs 说。
从任何模块外部注册的全局守卫(使用上面示例中的 useGlobalGuards())不能注入依赖项,因为这是在任何模块的上下文之外完成的。
这是他们的样本:
// app.module.js
import Module from '@nestjs/common';
import APP_GUARD from '@nestjs/core';
@Module(
providers: [
provide: APP_GUARD,
useClass: RolesGuard,
,
],
)
export class ApplicationModule
它成功了。现在我可以使用保护全局而不会出现依赖错误。
【讨论】:
你知道在模块上设置保护的方法,但在特定控制器上【参考方案4】:也许为时已晚,但我遇到了同样的问题并找到了解决方案。也许有更好的,但它对我来说工作正常:
将 KeysModule 定义为全局模块,你可以在 nestjs 文档中查看如何做到这一点:https://docs.nestjs.com/modules
之后你可以这样做:
import CanActivate, ExecutionContext, Injectable from '@nestjs/common';
@Injectable()
export class ApiGuard implements CanActivate
constructor(
@Inject('KeyService')
private readonly ks
)
const key = await this.ks.findKey();
"YOUR_CODE_HERE..."
希望它对您或将来会坚持这一点的人有所帮助。
【讨论】:
【参考方案5】:您可以像在任何带有Injectable
注释的对象中一样,在防护中注入服务。
如果您的 ApiGuard 需要 KeyService,您有两种选择:
【讨论】:
以上是关于在 Nest.JS 中将服务注入警卫的主要内容,如果未能解决你的问题,请参考以下文章
使用 websockets 和 Nest.js 的 Passport 会话身份验证未进行身份验证