【问题标题】:secretOrPrivateKey must have a value - NestJssecretOrPrivateKey 必须有一个值 - NestJs
【发布时间】:2022-10-23 06:07:10
【问题描述】:

在我的服务器中实现 jwt 时出现此错误。我正在使用 NestJs,并且正在关注文档。我一直在寻找有关此错误的解决方案,但似乎没有任何效果。 我已经将密钥存储在我的 .env 文件中,在我的 app.module 中添加了 ConfigModule.forRoot(),这样我就可以成功读取我的所有环境变量。这是我的代码,如果有人能指出我正确的方向。

app.module.ts

@Module({
  imports: [
    ConfigModule.forRoot(),
    TypeOrmModule.forRoot({
      type: 'postgres',
      host: process.env.DB_HOST,
      port: +process.env.DB_PORT,
      username: process.env.DB_USER,
      password: process.env.DB_PASS,
      database: process.env.DB_NAME,
      entities: ['dist/**/*.entity{.ts,.js}'],
      synchronize: false,
    }),
    UsersModule,
    AuthModule,
    PolsModule,
  ],
  controllers: [UsersController, AuthController, PolsController],
  providers: [UsersService, AuthService, PolsService, JwtService],
})
export class AppModule {}

auth.module.ts

@Module({
  imports: [
    UsersModule,
    PassportModule,
    JwtModule.register({
      secret: process.env.JWT_SECRET_KEY,
      signOptions: { expiresIn: '4h' },
    }),
  ],
  providers: [AuthService, UsersService, LocalStrategy, JwtStrategy],
  controllers: [AuthController],
})
export class AuthModule {}

身份验证控制器.ts

@Controller('auth')
export class AuthController {
  constructor(
    private authService: AuthService,
    private usersService: UsersService,
  ) {}

  @UseGuards(LocalAuthGuard)
  @Post()
  async login(@Request() req) {
    return this.authService.login(req.user);
  }
}

auth.service.ts

@Injectable()
export class AuthService {
  constructor(
    private usersService: UsersService,
    private jwtService: JwtService,
  ) {}

  async login(user: any) {
    const payload = { username: user.username, sub: user.id };
    console.log(process.env.JWT_SECRET_KEY);
    return {
      access_token: this.jwtService.sign(payload),
    };
  }
}

控制台错误

// console.log(process.env.JWT_SECRET_KEY)
fb8C47vylwS
[Nest] 50225  - 01/07/2022, 17:46:37   ERROR [ExceptionsHandler] secretOrPrivateKey must have a value
Error: secretOrPrivateKey must have a value
    at Object.module.exports [as sign] (/Users/user/dev/backend/pol-api/node_modules/jsonwebtoken/sign.js:107:20)
    at JwtService.sign (/Users/user/dev/backend/pol-api/node_modules/@nestjs/jwt/dist/jwt.service.js:28:20)
    at AuthService.login (/Users/user/dev/backend/pol-api/src/auth/auth.service.ts:26:37)
    at AuthController.login (/Users/user/dev/backend/pol-api/src/auth/auth.controller.ts:29:29)
    at /Users/user/dev/backend/pol-api/node_modules/@nestjs/core/router/router-execution-context.js:38:29
    at processTicksAndRejections (internal/process/task_queues.js:95:5)
    at /Users/user/dev/backend/pol-api/node_modules/@nestjs/core/router/router-execution-context.js:46:28
    at /Users/user/dev/backend/pol-api/node_modules/@nestjs/core/router/router-proxy.js:9:17

正如我所说,我尝试了在其他类似问题中发现的不同潜在解决方案(如this one),但没有一个答案对我有用。

【问题讨论】:

    标签: javascript jwt nest


    【解决方案1】:

    您在AppModule 中导入ConfigModule,但不是作为全局模块,因此您的AuthModule 不知道它。这就是为什么它不知道这个秘密。

    您也可以在AuthModule 中导入ConfigModule,或者从AppModule 中将其作为全局模块导入。

    @Module({
      imports: [
        ConfigModule.forRoot({
          isGlobal: true,
        }),
        ...
      ],
      ...
    })
    export class AppModule {}
    

    然后在AuthModule 中使用registerAsync 异步注册JwtModule。使用从ConfigModule 导出的ConfigService 注入的工厂。

    @Module({
      imports: [
        UsersModule,
        PassportModule,
        JwtModule.registerAsync({
          useFactory: (configService: ConfigService) => {
            return {
              secret: configService.get<string>('JWT_SECRET_KEY'),
              signOptions: { expiresIn: '60s' },
            };
          },
          inject: [ConfigService],
        }),
      ],
      ...
    })
    export class AuthModule {}
    

    AppModule 中导入的ConfigModule 在异步I/O 操作中读取.env 文件。通过异步注册JwtModule 并注入ConfigService 依赖项,您可以让它等待ConfigModule 被加载并且.env 文件被读取。只需使用ConfigService 读取环境变量并进行转换。

    有关使用 ConfigService 的更多信息可以在 NestJS 的文档中找到。

    https://docs.nestjs.com/techniques/configuration#using-the-configservice

    【讨论】:

    • 我已经按照你说的做了,但它似乎仍然不起作用。我设法通过直接在签名方法中添加私钥来使其工作。它有效,但对我来说似乎不对,我想弄清楚为什么我不能在模块中设置密钥。
    • 您是否将 .env 文件放在存储库的根目录中,并且 JWT 机密是否以正确的格式放入其中? (JWT_SECRET_KEY=value)。然后ConfigModule 应该读取该文件。
    • 是的,我做到了,实际上所有其他环境变量都被正确读取。只有这一个给出了一些问题。它现在可以这样做 async login(user: any) { const payload = { username: user.username, sub: user.id }; return { access_token: this.jwtService.sign(payload, { privateKey: process.env.JWT_SECRET_KEY, expiresIn: '4h', }), }; }
    • 将密钥传递给 jwtService.sign(...) 是可能的,但如果设置正确则没有必要。默认情况下,sign() 方法将在您导入 JwtModule 时使用密钥设置。如果你显式地将一个秘密传递给 sign() 方法,它将使用那个秘密,但它总是会回退到你在导入模块时传递的那个。请参阅@nest/jwt 模块中 jwt.service.ts 源代码中的第 114 行:github.com/nestjs/jwt/blob/…
    【解决方案2】:

    我参加聚会迟到了,但我只是想解决这个问题,然后找到了解决方案。

    问题可能出在 app.module.ts 中的这一行:

    providers: [UsersService, AuthService, PolsService, JwtService],
    

    不应将 JwtService 添加为提供程序。如果这样做,它似乎会重置所有已注册的选项。

    【讨论】:

      【解决方案3】:

      尝试从 app.module.ts 中的提供者中删除 JwtServiceAuthService。还要从 app.module.ts 中的控制器中删除 AuthController

      当我收到相同的错误消息时,这对我有用。虽然我还不完全确定为什么会这样(我对 NestJS 很陌生),但这是我的推理:

      您将AuthModule(已包含AuthControllerAuthService)传递到AppModule 中。通过在根 (AppModule) 级别再次添加AuthControllerAuthService,我相信您首先破坏了拥有AuthModule 的目的并且不使用模块上下文。通过将JwtService 添加到AppModule 提供程序,您可以用一个空的覆盖JwtServiceAuthModule 上下文中注册的JwtService

      同样,我是 NestJS 的新手,因此非常欢迎更正。

      【讨论】:

      猜你喜欢
      • 2019-02-23
      • 2020-02-28
      • 2022-06-18
      • 2021-01-17
      • 2010-12-26
      • 2021-10-29
      • 2017-02-05
      • 2012-02-03
      相关资源
      最近更新 更多