[英]JwtModule.registerAsync not working in NestJS
我正在開發一個 NestJS 項目,我需要將 JWT 與.env
配置一起使用。 它生成令牌,但在嘗試訪問安全 url(帶有授權標頭)時,它只返回未經授權的消息。
jwt.strategy.ts
import { Injectable, UnauthorizedException, Logger } from '@nestjs/common'; import { PassportStrategy } from '@nestjs/passport'; import { ExtractJwt, Strategy } from 'passport-jwt'; import { AuthService } from './auth.service'; import { JwtPayload } from './interfaces/jwt-payload.interface'; @Injectable() export class JwtStrategy extends PassportStrategy(Strategy) { constructor(private readonly authService: AuthService) { super({ jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), secretOrKey: process.env.JWT_SECRET_KEY, }); } async validate(payload: JwtPayload) { const user = await this.authService.validateUser(payload); if (;user) { throw new UnauthorizedException(); } return user; } }
auth.module.ts
import { Module } from '@nestjs/common'; import { AuthService } from './auth.service'; import { AuthController } from './auth.controller'; import { PassportModule } from '@nestjs/passport'; import { JwtModule } from '@nestjs/jwt'; import { JwtStrategy } from './jwt.strategy'; @Module({ imports: [ PassportModule.register({ defaultStrategy: 'jwt' }), JwtModule.registerAsync({ useFactory: async () => ({ secretOrPrivateKey: process.env.JWT_SECRET_KEY, signOptions: { expiresIn: process.env.JWT_EXPIRATION_TIME, }, }), }), ], providers: [AuthService, JwtStrategy], controllers: [AuthController], }) export class AuthModule {}
main.ts
import { NestFactory } from '@nestjs/core'; import * as dotenv from 'dotenv'; import { ApiModule } from './api/api.module'; import { Logger } from '@nestjs/common'; async function bootstrap() { dotenv.config({ path: './.env'}); const app = await NestFactory.create(ApiModule); const port = process.env.APP_PORT; await app.listen(port); Logger.log(`Server started on http://localhost:${port}`); } bootstrap();
看起來JwtModule.registerAsync
不適用於環境變量。 我嘗試了很多東西,但總是失敗。 如果我在auth.module.ts
中為 static 數據更改環境變量,那么它工作正常。 像這樣的東西:
secretOrPrivateKey: 'secretKey',
signOptions: {
expiresIn: 3600,
},
更新項目結構
- src
- api
- auth
- interfaces
jwt-payload.interface.ts
auth.controller.ts
auth.module.ts
auth.service.ts
jwt.strategy.ts
index.ts
api.module.ts
index.ts
main.ts
- test
.env
我的 main.ts 現在看起來像這樣。
import { NestFactory } from '@nestjs/core'; import * as dotenv from 'dotenv'; import { resolve } from 'path'; import { ApiModule } from './api/api.module'; import { Logger } from '@nestjs/common'; async function bootstrap() { dotenv.config({ path: resolve(__dirname, '../.env') }); const app = await NestFactory.create(ApiModule); const port = process.env.APP_PORT; await app.listen(port); Logger.log(`Server started on http://localhost:${port}`); } bootstrap();
您會看到我的.env
位於項目的根目錄中。
如果您使用config 模塊,您可以執行以下操作:
JwtModule.registerAsync({
useFactory: (config: ConfigService) => {
return {
secret: config.get<string>('JWT_SECRET_KEY'),
signOptions: {
expiresIn: config.get<string | number>('JWT_EXPIRATION_TIME'),
},
};
},
inject: [ConfigService],
}),
我在初始化JwtModule
也遇到了問題,這段代碼解決了它。
對我來說,你的代碼有效:
你的.env
文件在哪里? 你的配置dotenv.config({ path: './.env'});
等於默認配置dotenv.config();
在您的項目根目錄(而不是src
)中查找.env
文件的位置。
如果要將.env
文件放在src
目錄中,請使用以下配置
import { resolve } from 'path';
dotenv.config({ path: resolve(__dirname, '.env') });
我建議將它們封裝在ConfigService
,而不是直接使用您的環境變量,請參閱文檔。 這使得測試和重構變得更加容易。
假設您有一個.env
文件並且它位於正確的位置,為此您需要在一切之前配置 dotenv,甚至導入
// configure dotenv before every thing, even imports
import * as dotenv from 'dotenv';
import { resolve } from 'path';
dotenv.config({ path: resolve(__dirname, '../.env') });
// rest of the code
import { NestFactory } from '@nestjs/core';
import { ApiModule } from './api/api.module';
import { Logger } from '@nestjs/common';
async function bootstrap() {
const app = await NestFactory.create(ApiModule);
const port = process.env.APP_PORT;
await app.listen(port);
Logger.log(`Server started on http://localhost:${port}`);
}
bootstrap();
因為當你做這樣的事情時
import { ApiModule } from './api/api.module'
發生的情況是您正在運行文件./api/api.module
的代碼,該文件將如下所示(我正在使用您在問題中顯示的另一個文件,以便您更清楚)
import { Module } from '@nestjs/common';
import { AuthService } from './auth.service';
import { AuthController } from './auth.controller';
import { PassportModule } from '@nestjs/passport';
import { JwtModule } from '@nestjs/jwt';
import { JwtStrategy } from './jwt.strategy';
@Module({
imports: [
PassportModule.register({ defaultStrategy: 'jwt' }),
JwtModule.registerAsync({
useFactory: async () => ({
secretOrPrivateKey: process.env.JWT_SECRET_KEY,
signOptions: {
expiresIn: process.env.JWT_EXPIRATION_TIME,
},
}),
}),
],
providers: [AuthService, JwtStrategy],
controllers: [AuthController],
})
export class AuthModule {}
當你導入它時,整個文件被“執行”並且process.env
的引用在你設置dotenv
之前被“設置”。
因此,在“執行”使用process.env
的代碼之前,您需要“運行”設置dotenv
的代碼。
我仍然建議使用已經內置的配置,然后您應該使用異步方法並注入配置服務(就像其他一些答案一樣)。
但是如果你確實想使用process.env
, dotenv
在一切之前設置dotenv
是dotenv
的方法。
將parseInt()
用於process.env.JWT_EXPIRATION_TIME
。 expiresIn
參數應該是一個數字。 在你的情況下,它是字符串。
我最近在做這件事,就像你一樣,我嘗試了很多事情,但沒有人為我工作。相反,那個人做到了!
@Module({
imports: [
AnyModule,
JwtModule.registerAsync({
useFactory: async (config: ConfigService) => {
return {
secret: process.env.JWT_SECRET,
signOptions: { expiresIn: "120s" }
}
}
}),
]
我將JwtModule.registerAsync()方法與async useFactory一起使用,並且沒有注入ConfigService 。
然后進入我的AppModule.ts
@Module({
imports: [
ConfigModule.forRoot({
isGlobal: true,
})
有了這個,我們告訴ConfigModule它在全局范圍內工作,我們可以在任何模塊上使用它而無需導入
簡而言之,我們需要導入JwtModule並使用registerAsync方法調用userFactory object 也像異步一樣。 完成所有這些后, JwtModule等待AppModule.ts被創建以調用我們的process.env ,實際上是ConfigModule 。
感謝大家的回答和NestJs 文檔。
我希望這對你有用。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.