جاوااسکریپت - مشکلات ماژول JWT در NestJS
دارم با JWTModule در NestJS مشکل دارم. من به طور مداوم این خطا را دریافت میکنم، حتی زمانی که راز را مستقیماً در پیکربندی وارد میکنم به جای اینکه از فایل env خود استفاده کنم. نمیتوانم بفهمم چه چیزی را از دست دادهام.
Error: secretOrPrivateKey must have a value
مروری سریع بر اینکه این چگونه کار خواهد کرد.
- کلاینت به /auth/login با { username: string, password: string } فراخوانی میکند
- نگهبان LocalStrategy متد validateUser سرویس AuthService را فراخوانی میکند، که متد authenticateUser سرویس ldapServices را فراخوانی کرده و کاربر را باز میگرداند.
- از آنجا، من باید دادههای کاربر را از ldap دریافت کنم و آن را با برخی از دادههای کاربر که در mongo db خود داریم ترکیب کنم. همه اینها به خوبی کار میکند.
- پس از عبور از نگهبان، متد ورود AuthService را فراخوانی خواهد کرد. که باید بار مفید را با JWT ایجاد و امضا کند، با استفاده از JwtService (که توسط NestJS ارائه شده است). اینجاست که مشکل من رخ میدهد.
در اینجا فایلها و کدهای آنها آمده است:
اپ.کنترلر.تیاس
import { Controller, Get, Post, Request, UseGuards } from '@nestjs/common';
import { AppService } from './app.service';
import { AuthService } from './providers/auth/auth.service';
import { LocalAuthGuard } from './providers/auth/local.strategy';
@Controller()
export class AppController {
constructor(private readonly authService: AuthService) {}
@UseGuards(LocalAuthGuard)
@Post('/auth/login')
async login(@Request() req) {
return this.authService.login(req.user);
}
}
ماژول احراز هویت.ts
import { Module } from '@nestjs/common';
import { AuthService } from './auth.service';
import { AuthController } from './auth.controller';
import { UserModule } from './../../endpoints/user/user.module';
import { PassportModule } from '@nestjs/passport';
import { LocalStrategy } from './local.strategy';
import { JwtModule, JwtService } from '@nestjs/jwt';
import { UserService } from './../../endpoints/user/user.service';
import { LdapService } from './../ldap/ldap-service';
import { jwtConstants } from './constants';
import { JwtStrategy } from './jwt.strategy';
@Module({
imports: [
UserModule,
PassportModule,
JwtModule.register({
secret: '2I*5f5OE9tlGIbg*3Q*C',
signOptions: { expiresIn: '12h' },
}),
],
providers: [AuthService, LocalStrategy, LdapService],
controllers: [AuthController],
exports: [AuthService],
})
export class AuthModule {}
auth.service.ts
import { Injectable } from '@nestjs/common';
import { LdapService } from '../ldap/ldap-service';
import { UserService } from './../../endpoints/user/user.service';
import { JwtService } from '@nestjs/jwt';
@Injectable()
export class AuthService {
constructor(
private readonly ldapService: LdapService,
private readonly userService: UserService,
private readonly jwtService: JwtService
) {}
async validateUser(username: string, pass: string): Promise<any> {
const authenticated = await this.ldapService.authenticateUser(
username,
pass,
);
if (authenticated === true) {
console.log(authenticated, username, pass)
return await this.userService.getUserById(username);
}
return null;
}
async login(user: any) {
const payload = { ...user, sub: user.accountName };
console.log(process.env.JWT_SECRET, payload);
return {
access_token: this.jwtService.sign(payload),
};
}
}
local.strategy.ts
import { Strategy } from 'passport-local';
import { AuthGuard, PassportStrategy } from '@nestjs/passport';
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { AuthService } from './auth.service';
@Injectable()
export class LocalStrategy extends PassportStrategy(Strategy) {
constructor(private authService: AuthService) {
super();
}
async validate(username: string, password: string): Promise<any> {
const user = await this.authService.validateUser(username, password);
if (!user) throw new UnauthorizedException();
return user;
}
}
@Injectable()
export class LocalAuthGuard extends AuthGuard('local') {}
مطمئنم که چیزی کوچک را از دست دادهام. از کمک شما قدردانی میکنم.
پاسخ شماره ۱
پس از بحث در کامنتها مشخص شد که AuthService با اضافه شدن به بیش از یک آرایه providers دوباره ساخته میشود. از آنجا که JwtService گزینههای @Optional() برای تزریق دارد، در هنگام بازسازی خطا نمیداد، اما همان گزینههایی که به JwtModule.register منتقل شده بودند را دریافت نمیکرد. برای رفع این مشکل، AuthModule exports: [AuthService] را دارد و هر ماژولی که به AuthService نیاز دارد، imports: [AuthModule] را اضافه میکند تا اطمینان حاصل شود که تنها یک AuthService ایجاد میشود و JwtService مناسب با گزینههایی که به JwtModule منتقل شدهاند، در اختیار دارد.