使用
registerAsync
功能和 JwtModule
+JwtService
时遇到一些问题。我浏览了很多关于此的其他线程,似乎每个人都挂在ConfigModule
上,但我在这个项目中没有使用ConfigModule
。
让我从设置开始:
// secret-key.helper.ts
/*
Retrieve the JWT secret value from AWS Secrets Manager. This is used to
sign JWTs. Dont worry about imports, they're there.
*/
async function retrieveJwtSecret(): Promise<string> {
const secretClient = new SecretsManagerClient({
region: process.env.AWS_REGION,
});
const getSecretCom = new GetSecretValueCommand({
SecretId: process.env.JWT_SECRET_ARN,
});
const jwtSecret = (await secretClient.send(getSecretCom)).SecretString;
return jwtSecret;
}
// auth.module.ts
import { Module } from '@nestjs/common';
import { AuthService } from './auth.service';
import { AuthController } from './auth.controller';
import { JwtModule } from '@nestjs/jwt';
import { retrieveJwtSecret } from '../../utils/secret-key.helper';
@Module({
imports: [
JwtModule.registerAsync({
useFactory: async () => ({
global: true,
secret: await retrieveJwtSecret(),
signOptions: { expiresIn: '16h' },
}),
}),
],
controllers: [AuthController],
providers: [AuthService],
})
export class AuthModule {}
// my.guard.ts
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
import { Request } from 'express';
import { logEvent } from '../log-event.helper';
import { JwtService } from '@nestjs/jwt';
import { JwtPayloadDto } from 'src/models/auth/dto/jwt-payload.dto';
@Injectable()
export class MyGuard implements CanActivate {
constructor(private jwtService: JwtService) {}
private extractTokenFromHeader(request: Request): string | undefined {
const [type, token] = request.headers.authorization?.split(' ') ?? [];
return type === 'Bearer' ? token : undefined;
}
async canActivate(context: ExecutionContext): Promise<boolean> {
const req = context.switchToHttp().getRequest();
/* JWT Authentication */
const token = this.extractTokenFromHeader(req);
if (!token) {
logEvent('ERROR: No token found.', req.headers);
return false;
} else {
const payload = this.jwtService.decode(token) as JwtPayloadDto;
logEvent('Token found.', payload);
return true;
}
}
}
第一种方法是我如何从AWS秘密管理器检索我的JWT秘密密钥。第二个代码块是
auth
模块,显示 registerAsync
全局导入和 retrieveJwtSecret()
方法的使用(这就是导致问题的原因)。第三个代码块是我正在使用的守卫。
Nest 遇到正在导入/使用的 Guard 的第一个模块返回“无法解析依赖项”错误。当我从
registerAsync
切换到 register
时,将密钥拉入 main.ts
并手动将其放入 process.env
中,一切运行正常。
确切的错误是:
ERROR [ExceptionHandler] Nest can't resolve dependencies of the MyGuard (?).
Please make sure that the argument JwtService at index [0] is available in the BenefitsModule context.
Potential solutions: ...
通过使用
console.log
,我发现执行从 retrieveJwtSecret
函数开始,并且在运行时,它可以访问必要的 .env 变量。然而,它永远不会完全完成 const jwtSecret = await secretClient.send...
调用,我的猜测是,Nest 在收到秘密并完成设置 JwtModule
之前,会继续加载需要 JwtModule
的模块。
如果可能的话,我想远离我提到的
register
实现。有没有办法强制 Nest 等待 async
依赖项被 await
开启?
谢谢!
的
JwtModule.registerAsync
选项应该与useFactory
处于同一级别,而不是useFactory
返回的选项的一部分。所以你的模块应该是:
import { Module } from '@nestjs/common';
import { AuthService } from './auth.service';
import { AuthController } from './auth.controller';
import { JwtModule } from '@nestjs/jwt';
import { retrieveJwtSecret } from '../../utils/secret-key.helper';
@Module({
imports: [
JwtModule.registerAsync({
global: true,
useFactory: async () => ({
secret: await retrieveJwtSecret(),
signOptions: { expiresIn: '16h' },
}),
}),
],
controllers: [AuthController],
providers: [AuthService],
})
export class AuthModule {}
这将使
JwtModule
实际上全球化。