feat: v2 rate limiting (#16882)
* refactor: pass redis storage to throttler guard * chore: upgrade throttler to latest * feat: ApiKey RateLimit table * chore: upgrade redis storage throttler * feat: rate limit by api key * refactor: on delete api key cascade rate limit * fix: permissions guard work with oauth credentials * chore: set rate limit in env * tests: throttler * feat: include rate limit name in response * fix: correctly handle multiple rate limits * chore: remove unused import * delete migrations * chore: prisma migration * doc * dummy * fix: permissions guard unit test * refactor: remove route specific @Throttles * fix: permissions guard
This commit is contained in:
@@ -13,12 +13,12 @@ import { JwtModule } from "@/modules/jwt/jwt.module";
|
||||
import { PrismaModule } from "@/modules/prisma/prisma.module";
|
||||
import { RedisModule } from "@/modules/redis/redis.module";
|
||||
import { RedisService } from "@/modules/redis/redis.service";
|
||||
import { ThrottlerStorageRedisService } from "@nest-lab/throttler-storage-redis";
|
||||
import { BullModule } from "@nestjs/bull";
|
||||
import { MiddlewareConsumer, Module, NestModule, RequestMethod } from "@nestjs/common";
|
||||
import { ConfigModule } from "@nestjs/config";
|
||||
import { APP_GUARD, APP_INTERCEPTOR } from "@nestjs/core";
|
||||
import { seconds, ThrottlerModule } from "@nestjs/throttler";
|
||||
import { ThrottlerStorageRedisService } from "nestjs-throttler-storage-redis";
|
||||
|
||||
import { AppController } from "./app.controller";
|
||||
|
||||
@@ -34,16 +34,19 @@ import { AppController } from "./app.controller";
|
||||
BullModule.forRoot({
|
||||
redis: `${process.env.REDIS_URL}${process.env.NODE_ENV === "production" ? "?tls=true" : ""}`,
|
||||
}),
|
||||
// Rate limiting here is handled by the CustomThrottlerGuard
|
||||
ThrottlerModule.forRootAsync({
|
||||
imports: [RedisModule],
|
||||
inject: [RedisService],
|
||||
useFactory: (redisService: RedisService) => ({
|
||||
// note(Lauris): IMPORTANT: rate limiting is enforced by CustomThrottlerGuard, but we need to have at least one
|
||||
// entry in the throttlers array otherwise CustomThrottlerGuard is not invoked at all. If we specify only ThrottlerModule
|
||||
// without .forRootAsync then throttler options are not passed to CustomThrottlerGuard containing redis connection etc.
|
||||
// So we need to specify at least one dummy throttler here and CustomThrottlerGuard is actually handling the default and custom rate limits.
|
||||
throttlers: [
|
||||
{
|
||||
name: "long",
|
||||
ttl: seconds(60), // Time to live for the long period in seconds
|
||||
limit: 120, // Maximum number of requests within the long ttl
|
||||
name: "dummy",
|
||||
ttl: seconds(60),
|
||||
limit: 120,
|
||||
},
|
||||
],
|
||||
storage: new ThrottlerStorageRedisService(redisService.redis),
|
||||
@@ -56,6 +59,13 @@ import { AppController } from "./app.controller";
|
||||
],
|
||||
controllers: [AppController],
|
||||
providers: [
|
||||
{
|
||||
provide: ThrottlerStorageRedisService,
|
||||
useFactory: (redisService: RedisService) => {
|
||||
return new ThrottlerStorageRedisService(redisService.redis);
|
||||
},
|
||||
inject: [RedisService],
|
||||
},
|
||||
{
|
||||
provide: APP_INTERCEPTOR,
|
||||
useClass: ResponseInterceptor,
|
||||
|
||||
Reference in New Issue
Block a user