JwtModule.registerAsync 在 NestJS 中不起作用
Posted
技术标签:
【中文标题】JwtModule.registerAsync 在 NestJS 中不起作用【英文标题】:JwtModule.registerAsync not working in NestJS 【发布时间】:2019-08-04 12:49:57 【问题描述】:我正在开发一个 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
中为静态数据更改环境变量,那么它工作正常。
像这样的:
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
在项目的根目录中。
【问题讨论】:
【参考方案1】:对我来说,你的代码有效:
您的.env
文件在哪里?
您的配置dotenv.config( path: './.env');
等于默认配置dotenv.config();
,其中.env
文件在您的项目根目录(而不是src
)中查找。
如果你想把你的.env
文件放到src
目录下,使用下面的配置
import resolve from 'path';
dotenv.config( path: resolve(__dirname, '.env') );
我建议不要直接使用您的环境变量,而是将它们封装在ConfigService
中,请参阅docs。这使得测试和重构变得更加容易。
【讨论】:
这很奇怪,我不想在我的本地主机上工作。也许节点版本或什么?我有节点版本 v11.5.0 你把你的.env
文件放在哪里了?
我会用我的项目结构更新我的帖子。我想知道 nodemon 是否与此有关
别这么认为,codesandbox的例子也运行nodemon
我不知道它可能是什么:S。当然,我在本地也有同样的东西,但它每次都会引发未经授权的事情。【参考方案2】:
如果你使用config module,你可以这样做:
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 文件中读取密钥时遇到问题,这个解决方案对我有用。【参考方案3】:TL;DR
假设您有一个 .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
的代码。
观察:
我仍然建议使用已经内置的Configuration,然后您应该使用异步方法并注入配置服务(就像其他一些答案一样)。
但如果你确实想使用process.env
,那么在一切之前设置dotenv
是可行的方法。
【讨论】:
以上是关于JwtModule.registerAsync 在 NestJS 中不起作用的主要内容,如果未能解决你的问题,请参考以下文章
NOIP 2015 & SDOI 2016 Round1 & CTSC 2016 & SDOI2016 Round2游记