我们希望为Grails 3应用程序实施API速率限制。我们为此目的使用拦截器和redis。但是,有一个问题是为每个进入Grails的请求打开hibernate会话(打开数据库连接)。这是一种我们不能忽视的资源消耗,因为它可以通过简单的攻击轻松达到MySQL连接限制。
问题是如何强制Grails不为某些url /拦截器打开hibernate会话的最佳方法是什么。我知道像konghq.com这样的API网关,这对我们来说不是一个选择。
我也知道实施GrailsOpenSessionInViewInterceptor
的{{1}}负责会话管理。那么它是唯一一个覆盖这个拦截器的选项吗?如何为那些符合速率限制的请求打开hibernate会话?
答案 0 :(得分:0)
最后,我覆盖GrailsOpenSessionInViewInterceptor
,只有在满足速率限制的情况下才打开hibernate会话。
import org.grails.web.servlet.mvc.GrailsWebRequest
import org.grails.web.util.GrailsApplicationAttributes
import org.springframework.web.context.request.WebRequest
import javax.servlet.http.HttpServletRequest
class MyOpenSessionInViewInterceptor extends GrailsOpenSessionInViewInterceptor {
@Override
void preHandle(WebRequest request) throws DataAccessException {
GrailsWebRequest grailsRequest = (GrailsWebRequest) request.getAttribute(GrailsApplicationAttributes.WEB_REQUEST,
WebRequest.SCOPE_REQUEST)
HttpServletRequest servletRequest = grailsRequest.request
// intercept /api/* requests
if (!servletRequest.requestURI.startsWith('/api')) {
// if rate limits exceeded
if (checkRateLimits) {
servletRequest.setAttribute('MY_RATE_LIMITS_EXCEEDED', true)
return
}
super.preHandle(request)
}
}
}
别忘了在resource.groovy中注入你的bean。
// Place your Spring DSL code here
beans = {
// intercept opening of hibernate cache
openSessionInViewInterceptor(MyOpenSessionInViewInterceptor) {
hibernateDatastore = ref('hibernateDatastore')
}
}
我把它与内部grails拦截器放在一起,我从Spring开放会话拦截器检查传递属性。
class V1RateLimitInterceptor {
V1RateLimitInterceptor() {
match(namespace: 'api')
}
boolean before() {
// request rate limits
boolean rateLimit = (boolean) request.getAttribute('MY_RATE_LIMITS_EXCEEDED')
if (rateLimit) {
return false
}
return true
}
}
这对我们来说是暂时的解决方案,因为我们将来会使用像konghq.com这样的API网关。