NestJs 身份验证教程在实施本地策略后总是返回 401 Unauthorized(使用浏览器时)

问题描述 投票:0回答:1

我想做的是使用护照进行简单的身份验证,如本教程所示:https://docs.nestjs.com/techniques/authentication

我一直遵循本教程,并且在使用 Insomnia、Swagger 或 Postman 时有效。后来我在react中创建了前端,但请求总是返回

POST http://localhost:3333/auth/login 401 (Unauthorized)

{statusCode: 401, message: 'Unauthorized'}
.

其他路由如

/user/getAll
在swagger/postman和浏览器中正常工作。但身份验证路线
auth/login
仅适用于swagger/postman

我在这里遗漏了什么吗?

我寻找解决方案 4 小时,但我找到的所有解决方案都不适用于我的项目。

main.ts

async function bootstrap() {
  const app = await NestFactory.create(AppModule);

  const corsOptions = {
    origin: '*',
    credentials: true,
    allowedHeaders: 'Content-Type, Accept, Origin',
    preflightContinue: false,
    methods: 'GET,HEAD,PUT,PATCH,POST,DELETE',
  };

  app.enableCors(corsOptions);
  app.use(helmet());
  app.use(cookieParser());
  // app.use(csurf());

  const config = new DocumentBuilder()
    .setTitle('Nyx Swagger')
    .setDescription('The Nyx API description')
    .setVersion('1.0')
    .build();
  const document = SwaggerModule.createDocument(app, config);
  SwaggerModule.setup('api', app, document);

  app.useGlobalPipes(new ValidationPipe());

  await app.listen(process.env.PORT || 3333);
}
bootstrap();

app.module.ts

@Module({
  imports: [
    MongooseModule.forRoot(
      'mongodb+srv://USERNAME:[email protected]/db-beta?retryWrites=true&w=majority',
      {
        useNewUrlParser: true,
        useUnifiedTopology: true,
        useFindAndModify: false,
        useCreateIndex: true,
      },
    ),
    ThrottlerModule.forRoot({
      ttl: 60,
      limit: 10,
    }),
    AuthModule,
    UsersModule,
  ],
  controllers: [AppController],
  providers: [
    LocalStrategy,
  ],
})
export class AppModule {}

app.controller.ts

@Controller()
export class AppController {
  constructor(private authService: AuthService) {}

  @UseGuards(LocalAuthGuard)
  @Post('auth/login')
  async login(
    @Body() _: MakeAuthDto,
    @Request() req,
    @Res({ passthrough: true }) res,
  ) {
    const access_token = await this.authService.login(req.user, req.ip);
    res.cookie('jwt', access_token);
    return req.user;
  }
}

auth.module.ts

@Module({
  imports: [
    UsersModule,
    PassportModule,
    JwtModule.register({
      secret: process.env.JWTSECRET,
      signOptions: { expiresIn: '7d' },
    }),
  ],
  providers: [AuthService, LocalStrategy, JwtStrategy],
  exports: [AuthService],
})
export class AuthModule {}

auth.service.ts

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

  async validateUser(email: string, pass: string): Promise<UserDocument | any> {
    const user = await this.usersService.findOne({ email } as any, true);

    if (
      user &&
      (await user.compareHash(pass)) &&
      user.hasAccess &&
      !user.deleted
    ) {
      const {
        password,
        verificationCode,
        ips,
        deleted,
        hasAccess,
        usageTerms,
        usageTermsHistory,
        ...result
      } = user.toObject();
      return result;
    }
    return null;
  }

  async login(user: UserDocument, ip: string): Promise<string> {
    const payload = {
      email: user.email,
      sub: user._id,
      name: user.name,
      roles: user.roles,
    };
    await this.usersService.updateLastLogin(user._id, ip);
    return this.jwtService.sign(payload);
  }
}

jwt.strategy.ts

const cookieExtractor = function (req) {
  let token = null;
  if (req && req.cookies) {
    token = req.cookies['jwt'];
  }
  return token;
};

@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
  constructor() {
    super({
      jwtFromRequest: ExtractJwt.fromExtractors([cookieExtractor]),
      ignoreExpiration: false,
      secretOrKey: process.env.JWTSECRET,
    });
  }

  async validate(payload: any) {
    return {
      _id: payload.sub,
      name: payload.name,
      email: payload.email,
      roles: payload.roles,
    };
  }
}

本地.strategy.ts

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

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

前端请求

export const AuthAPI = {
  async login(data) {
    const response = await fetch(`${API_URL}/auth/login`, {
      method: "POST",
      headers: { "Content-type": "application/json", accept: "*/*" },
      // credentials: "include",
      body: JSON.stringify(data),
    });

    const json = await response.json();

    return json;
  },
};

打印:

reactjs nestjs passport.js passport-local
1个回答
0
投票

尝试删除您的 dist 文件夹,然后重新启动服务器

© www.soinside.com 2019 - 2024. All rights reserved.