1

我正在开发一个 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 {}

主要的.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,那么它工作正常。像这样的东西:

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();

您会看到 my.env位于项目的根目录中。

4

3 回答 3

7

如果您使用配置模块,您可以执行以下操作:

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,这段代码解决了它。

于 2021-03-13T17:19:04.923 回答
1

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.

因此,您需要在dotenv“执行”您使用的代码之前“运行”设置 的代码process.env

观察:

我仍然建议使用已经内置的配置,然后您应该使用异步方法并注入配置服务(就像其他一些答案一样)。

但是,如果您确实想使用process.envdotenv在一切之前设置是要走的路。

于 2021-04-15T21:32:25.190 回答
0

对我来说,您的代码有效:

编辑 Nest.js JWT 身份验证

你的.env文件在哪里?您的配置dotenv.config({ path: './.env'});等于在项目根目录(而不是 )中查找文件的dotenv.config();默认.env配置src

如果要将.env文件放在src目录中,请使用以下配置

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

我建议不要直接使用您的环境变量,而是将它们封装在 a 中ConfigService,请参阅文档。这使得测试和重构变得更加容易。

于 2019-03-13T23:09:17.870 回答