fix: throttle ip tracker

Signed-off-by: Innei <i@innei.in>
This commit is contained in:
Innei
2024-02-21 21:08:36 +08:00
parent c2e2f98510
commit c82cb8ff54
8 changed files with 43 additions and 8 deletions

View File

@@ -91,7 +91,7 @@ export class AllExceptionsFilter implements ExceptionFilter {
body: `IP: ${ip}`,
})
return response.status(444).send({
return response.status(429).send({
message: '请求过于频繁,请稍后再试',
})
}

View File

@@ -1,18 +1,46 @@
import type { ExecutionContext } from '@nestjs/common'
import type { ThrottlerOptions } from '@nestjs/throttler'
import type { FastifyBizRequest } from '~/transformers/get-req.transformer'
import { Injectable } from '@nestjs/common'
import { ThrottlerGuard } from '@nestjs/throttler'
import { ThrottlerException, ThrottlerGuard } from '@nestjs/throttler'
import { getNestExecutionContextRequest } from '~/transformers/get-req.transformer'
import { getIp } from '~/utils'
@Injectable()
export class ExtendThrottlerGuard extends ThrottlerGuard {
async canActivate(context: ExecutionContext): Promise<boolean> {
protected async shouldSkip(context: ExecutionContext): Promise<boolean> {
const req = getNestExecutionContextRequest(context)
if (req.user) {
return true
}
return super.canActivate(context)
return super.shouldSkip(context)
}
protected async getTracker(req: FastifyBizRequest) {
return getIp(req.raw)
}
}
export class WsExtendThrottlerGuard extends ExtendThrottlerGuard {
async handleRequest(
context: ExecutionContext,
limit: number,
ttl: number,
throttler: ThrottlerOptions,
): Promise<boolean> {
const client = context.switchToWs().getClient()
const ip = client._socket.remoteAddress
const key = this.generateKey(context, ip, throttler.name || 'ws-default')
const { totalHits } = await this.storageService.increment(key, ttl)
console.log('totalHits', totalHits)
if (totalHits > limit) {
throw new ThrottlerException()
}
return true
}
}

View File

@@ -38,7 +38,7 @@ import {
parseRoomName,
} from './activity.util'
declare module '~/utils/socket.util' {
declare module '~/types/socket-meta' {
interface SocketMetadata {
presence?: ActivityPresence
}

View File

@@ -7,9 +7,10 @@ import type {
} from '@nestjs/websockets'
import type SocketIO from 'socket.io'
import { forwardRef, Inject } from '@nestjs/common'
import { forwardRef, Inject, UseGuards } from '@nestjs/common'
import { SubscribeMessage, WebSocketGateway } from '@nestjs/websockets'
import { WsExtendThrottlerGuard } from '~/common/guards/throttler.guard'
import { LOG_DIR } from '~/constants/path.constant'
import { JWTService } from '~/processors/helper/helper.jwt.service'
import { CacheService } from '~/processors/redis/cache.service'
@@ -22,6 +23,7 @@ import { createAuthGateway } from '../shared/auth.gateway'
const AuthGateway = createAuthGateway({ namespace: 'admin', authway: 'jwt' })
@WebSocketGateway<GatewayMetadata>({ namespace: 'admin' })
@UseGuards(WsExtendThrottlerGuard)
export class AdminEventsGateway
extends AuthGateway
implements OnGatewayConnection, OnGatewayDisconnect

View File

@@ -1,4 +1,4 @@
import type { SocketMetadata } from '~/utils/socket.util'
import type { SocketMetadata } from '~/types/socket-meta'
import type { RemoteSocket, Socket } from 'socket.io'
import type {
DecorateAcknowledgementsWithMultipleResponses,

View File

@@ -14,6 +14,7 @@ import type {
import type { SocketType } from '../gateway.service'
import type { EventGatewayHooks } from './hook.interface'
import { UseGuards } from '@nestjs/common'
import {
ConnectedSocket,
MessageBody,
@@ -22,6 +23,7 @@ import {
WebSocketServer,
} from '@nestjs/websockets'
import { WsExtendThrottlerGuard } from '~/common/guards/throttler.guard'
import { BusinessEvents } from '~/constants/business-event.constant'
import { RedisKeys } from '~/constants/cache.constant'
import { CacheService } from '~/processors/redis/cache.service'
@@ -33,7 +35,7 @@ import { BroadcastBaseGateway } from '../base.gateway'
import { GatewayService } from '../gateway.service'
import { MessageEventDto, SupportedMessageEvent } from './dtos/message'
declare module '~/utils/socket.util' {
declare module '~/types/socket-meta' {
interface SocketMetadata {
sessionId: string
@@ -42,6 +44,8 @@ declare module '~/utils/socket.util' {
}
const namespace = 'web'
@UseGuards(WsExtendThrottlerGuard)
@WebSocketGateway<GatewayMetadata>({
namespace,
})

View File

@@ -23,6 +23,7 @@ export const getIp = (request: FastifyRequest | IncomingMessage) => {
headers['X-Real-IP'] ||
headers['x-real-ip'] ||
req?.ip ||
req?.ips?.[0] ||
req?.raw?.connection?.remoteAddress ||
req?.raw?.socket?.remoteAddress ||
undefined