You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NestJS Passport Local认证请求无响应问题求助

NestJS Passport LocalAuthGuard 请求挂起问题

问题现象

基于NestJS官方文档实现Passport认证系统时,使用LocalAuthGuard处理登录请求时,请求始终处于等待响应状态。调试发现:

  • LocalAuthGuard.canActivate()中调用super.canActivate(context)返回Promise { <pending> }
  • LocalStrategy的validate方法从未执行

相关代码片段

auth.module.ts

@Module({
  controllers: [AuthController],
  providers: [AuthService, LocalStrategy, JwtStrategy, RefreshJwtStrategy],
  imports: [
    UsersModule,
    ConfigModule,
    PassportModule,
    JwtModule.registerAsync({
      inject: [ConfigService],
      imports: [ConfigModule],
      useFactory: (configService: ConfigService) => ({
        secret: configService.get<string>('JWT_SECRET_KEY'),
        signOptions: {
          expiresIn: configService.get<string>('JWT_ACCESS_TOKEN_TTL'),
        },
      }),
    }),
  ],
})
export class AuthModule {}

auth.service.ts

export class AuthService {
  constructor(
    private readonly userRepository: UsersRepository,
    private readonly jwtService: JwtService,
    private readonly configService: ConfigService,
  ) {}

  /**
   * Return user with given username and matching password.
   * @param email User's email.
   * @param password User's password.
   */
  public async validateUser(
    email: string,
    password: string,
  ): Promise<User | null> {
    const user = await this.userRepository.getUserByEmail(email);

    if (user && (await compare(password, user.password))) return user;

    return null;
  }

  public async createTokenPair(user: any): Promise<TokenPairEntity> {
    // 省略实现
  }
}

users.repository.ts

@Injectable()
export class UsersRepository {
  public constructor(
    @InjectModel(User.name) private readonly userModel: Model<User>,
  ) {}

  public async getUserByEmail(email: string): Promise<User | null> {
    return this.userModel.findOne({ email }).select(['-__v']).exec();
  }

  // 省略其他方法
}

auth.strategy.ts(错误版本)

@Injectable()
export class LocalStrategy extends PassportStrategy(Passport, 'local') {
  public constructor(private readonly authService: AuthService) {
    super({ usernameField: 'email', passwordField: 'password' });
  }

  public async validate(email: string, password: string): Promise<User> {
    const user = await this.authService.validateUser(email, password);

    if (!user) throw new UnauthorizedException();

    return user;
  }
}

auth.guards.ts

export class LocalAuthGuard extends AuthGuard('local') {
  public canActivate(
    context: ExecutionContext,
  ): boolean | Promise<boolean> | Observable<boolean> {
    const result = super.canActivate(context);
    console.log(result);
    return result;
  }
}

auth.controller.ts

@Controller('auth')
export class AuthController {
  public constructor(private readonly authService: AuthService) {}

  @Post('login')
  @UseGuards(LocalAuthGuard)
  public async login(@Request() req: Req): Promise<TokenPairEntity> {
    return this.authService.createTokenPair(req.user);
  }
}

问题原因及解决方案

1. 核心错误:LocalStrategy继承参数错误

PassportStrategy的第一个参数必须是具体的Passport策略实现(如passport-local的Strategy),而非Passport类本身。错误的参数导致Passport无法初始化认证流程,Promise一直处于pending状态。

修正后的auth.strategy.ts:

import { Injectable, UnauthorizedException } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { Strategy } from 'passport-local'; // 导入正确的Strategy
import { AuthService } from './auth.service';

@Injectable()
export class LocalStrategy extends PassportStrategy(Strategy, 'local') {
  constructor(private readonly authService: AuthService) {
    super({ usernameField: 'email', passwordField: 'password' });
  }

  async validate(email: string, password: string): Promise<any> {
    const user = await this.authService.validateUser(email, password);
    if (!user) {
      throw new UnauthorizedException();
    }
    return user;
  }
}

2. 确保请求体解析正常

Local策略需要从请求体中获取email和password,需确保NestJS已启用请求体解析。在main.ts中确认以下代码存在:

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import * as express from 'express';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  // 启用请求体解析
  app.use(express.json());
  app.use(express.urlencoded({ extended: true }));
  await app.listen(3000);
}
bootstrap();

注:NestJS默认会启用这些解析中间件,但如果有自定义配置可能需要手动添加。

3. 检查依赖完整性

确保已安装所有必需依赖:

npm install passport passport-local @nestjs/passport @nestjs/jwt bcrypt

内容的提问来源于stack exchange,提问作者Togrul

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 04:37:11