
요청 제한을 정의하는 Bucket을 설정하는 RateLimitConfig 클래스를 추가한다.
1분당 10회 요청을 허용하도록 하고 빈으로 관리한다.
@Configuration
class RateLimitConfig {
@Bean
fun rateLimitBucket(): Bucket {
// 1분당 최대 10회의 요청을 허용
val limit = Bandwidth.classic(10, Refill.greedy(10, Duration.ofMinutes(1)))
return Bucket4j.builder().addLimit(limit).build()
}
}
요청이 올 때마다 Bucket에서 토큰을 소모하며, 토큰이 부족할 경우 접근을 차단하는 RateLimitFilter를 추가한다.
각 요청마다 bucket.tryConsume(1)을 호출하여 토큰을 소모한다. 남은 토큰이 없을 경우 403 Forbidden을 반환한다.
@Component
class RateLimitFilter(private val bucket: Bucket) : OncePerRequestFilter() {
@Throws(ServletException::class, IOException::class)
override fun doFilterInternal(
request: HttpServletRequest,
response: HttpServletResponse,
filterChain: FilterChain
) {
if (bucket.tryConsume(1)) {
filterChain.doFilter(request, response)
} else {
response.status = HttpServletResponse.SC_FORBIDDEN
response.writer.write("Too many requests - try again later")
}
}
}
@Configuration
@EnableWebSecurity
class SecurityConfig(
private val jwtTokenProvider: JwtTokenProvider,
private val rateLimitFilter: RateLimitFilter,
@Value("\${cors.allowed.origins}") private val allowedOrigins: List<String>
) {
@Bean
fun filterChain(http: HttpSecurity): SecurityFilterChain {
http
// ... 이전 코드
.addFilterBefore(
rateLimitFilter, // RateLimitFilter 추가
SecurityContextHolderAwareRequestFilter::class.java
)
// ... 이전 코드
return http.build()
}
@Bean
fun customAuthenticationEntryPoint(): AuthenticationEntryPoint {
return CustomAuthenticationEntryPoint()
}
// ... 이전 코드
}