簡體   English   中英

JwtModule.registerAsync 在 NestJS 中不起作用

[英]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也遇到了問題,這段代碼解決了它。

對我來說,你的代碼有效:

編輯 Nest.js JWT 身份驗證

你的.env文件在哪里? 你的配置dotenv.config({ path: './.env'}); 等於默認配置dotenv.config(); 在您的項目根目錄(而不是src )中查找.env文件的位置。

如果要將.env文件放在src目錄中,請使用以下配置

import { resolve } from 'path';
dotenv.config({ path: resolve(__dirname, '.env') });

我建議將它們封裝在ConfigService ,而不是直接使用您的環境變量,請參閱文檔 這使得測試和重構變得更加容易。

TL; 博士

假設您有一個.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.envdotenv在一切之前設置dotenvdotenv的方法。

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM