NestJS - 错误:未知的身份验证策略“本地”

adh*_*yan 6 javascript authentication passport-local passport.js nestjs

这些是我拥有的部分 NestJS 代码片段。我正在尝试实施护照本地策略来获取用户名和密码。使用身份验证防护时,我在控制器文件中收到 -Error: Unknown authentication Strategy "local"。

AuthModule.ts

import { Module } from '@nestjs/common';
import { JwtModule } from '@nestjs/jwt';
import { PassportModule } from '@nestjs/passport';
import { UserModule } from 'src/user/user.module';
import { JwtAuthController } from './jwt-auth.controller';
import { JwtAuthService } from './jwt-auth.service';
import { JwtStrategy } from './jwt.strategy';
import { LocalStrategy } from './local.strategy';

@Module({
  imports: [
    UserModule,
    PassportModule,
    JwtModule.register({
      secret: process.env.SECRETKEY,
      signOptions: { expiresIn: '3600s' }
    })
  ],
  controllers: [JwtAuthController],
  providers: [JwtAuthService, LocalStrategy, JwtStrategy],
  exports: [JwtAuthService],
})
export class JwtAuthModule {}
Run Code Online (Sandbox Code Playgroud)

本地策略.ts

import { Strategy } from 'passport-local';
import { PassportStrategy } from '@nestjs/passport';
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { JwtAuthService } from './jwt-auth.service';

@Injectable()
export class LocalStrategy extends PassportStrategy(Strategy, 'local') {
  constructor(private authService: JwtAuthService) {
    super();
  }

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

应用程序控制器.ts

import { Body, Controller, Get, Post, Req, UnauthorizedException, UseGuards } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { JwtAuthService } from './jwt-auth/jwt-auth.service';

@Controller()
export class AppController {

  constructor(private readonly authService: JwtAuthService)  {}
  
  @UseGuards(AuthGuard('local'))
  @Post('/auth/login')
  async login(@Req() req) {
    return this.authService.login(req.user)
  }
  
}
Run Code Online (Sandbox Code Playgroud)

我在调用 /auth/login API 时收到以下错误

[Nest] 26753  - 10/31/2021, 22:08:18   ERROR [ExceptionsHandler] Unknown authentication strategy "local"
Error: Unknown authentication strategy "local"
Run Code Online (Sandbox Code Playgroud)

我错过了什么吗?提前致谢。

wkr*_*ger 5

这么老的问题了,没有答案……

就我而言,我遇到了某种循环依赖问题。或者至少看起来是这样的。循环 deps 可以位于嵌套端,甚至可以位于 node.js require 端(在第二种情况下,我们最终会得到空导入)。

情况1:

@Injectable()
export class MyLocalStrategy extends PassportStrategy(PassportLocalStrategy) {
  hello = 'hello'

  constructor(private authService: AuthService) {
    console.log('load local strategy')
  }
}


@Module({
  imports: [
    CommonModule,
    PassportModule,
    JwtModule.registerAsync({
      async useFactory(config: ConfigService) {
        const jwtSecret = config.get('APP_KEY')
        const expiresIn = config.get('AUTH_TOKEN_EXPIRED')
        return {
          secret: jwtSecret,
          signOptions: {
            expiresIn,
          },
        }
      },
      inject: [ConfigService],
    }),
  ],
  providers: [
    RoleService,
    JwtStrategy,
    JwtService,
    AuthService,
  ],
  controllers: [AuthController],
  exports: [AuthService],
})
export class AuthModule {
  constructor(private moduleRef: ModuleRef) {}

  onModuleInit() {
    const moduleRef = this.moduleRef
    console.log('init auth module')
    const local = moduleRef.get(MyLocalStrategy)
    const auth = moduleRef.get(AuthService)
    console.log('my modules', { local, auth }, local?.hello)
  }
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,“加载本地策略”从未被记录。然而“我的模块”记录了一个空的 localStrategy 实例,没有我的“hello”属性。诡异的!

我通过将类实例化移至工厂提供程序并要求与ModuleRef. 以下摘录效果很好。

@Module({
  imports: [
    CommonModule,
    PassportModule,
    JwtModule.registerAsync({
      async useFactory(config: ConfigService) {
        const jwtSecret = config.get('APP_KEY')
        const expiresIn = config.get('AUTH_TOKEN_EXPIRED')
        return {
          secret: jwtSecret,
          signOptions: {
            expiresIn,
          },
        }
      },
      inject: [ConfigService],
    }),
  ],
  providers: [
    RoleService,
    JwtStrategy,
    JwtService,
    AuthService,
    {
      provide: MyLocalStrategy,
      useFactory: (moduleRef: ModuleRef) => {
        const auth = moduleRef.get(AuthService)
        console.log('local strat factory', { auth })
        return new MyLocalStrategy(auth)
      },
      inject: [ModuleRef],
    },
  ],
  controllers: [AuthController],
  exports: [AuthService],
})
export class AuthModule {
  constructor(private moduleRef: ModuleRef) {}

  onModuleInit() {
    const moduleRef = this.moduleRef
    console.log('init auth module')
    const local = moduleRef.get(MyLocalStrategy)
    const auth = moduleRef.get(AuthService)
    console.log('local', { local, auth }, local?.hello)
  }
}
Run Code Online (Sandbox Code Playgroud)

我还尝试了直接工厂+注入AuthService(通过providers数组,而不是使用ModuleRef)。我得到了一个 null AuthService。

可能是对 Node.js 模块导入的一些依赖循环,但 eslint 或 Nest 都不会说什么。


小智 1

修复错误https://github.com/nestjs/nest/issues/4646

文件 AUTH.ts

enter code here

import { Module } from '@nestjs/common';
import { JwtModule } from '@nestjs/jwt';
import { PassportModule } from '@nestjs/passport';
import { UserModule } from 'src/user/user.module';
import { JwtAuthController } from './jwt-auth.controller';
import { JwtAuthService } from './jwt-auth.service';
import { JwtStrategy } from './jwt.strategy';
import { LocalStrategy } from './local.strategy';

@Module({
imports: [
UserModule,
PassportModule.register({defaultStrategy:'local'}),
JwtModule.register({
  secret: process.env.SECRETKEY,
  signOptions: { expiresIn: '3600s' }
})
],
controllers: [JwtAuthController],
providers: [JwtAuthService, LocalStrategy, JwtStrategy],
exports: [JwtAuthService],
})
export class JwtAuthModule {}
Run Code Online (Sandbox Code Playgroud)