Grails - 不要为某些请求路径打开休眠会话
Grails - do not open hibernate session for certain request path
我们想对 Grails 3 应用程序实施 API 速率限制。为此,我们使用拦截器和 redis。然而,对于每个到达 Grails 的请求,存在打开休眠会话(打开数据库连接)的问题。这是我们不能忽视的资源消耗,因为它可以通过简单的攻击轻松达到 MySQL 连接限制。
问题是强制 Grails 不为某些 urls/interceptors 打开休眠会话的最佳方法是什么。我知道像 konghq.com 这样的 API 网关,这不是我们的选择。
我也知道 GrailsOpenSessionInViewInterceptor
实施 OpenSessionInViewInterceptor
负责会话管理。那么它是覆盖这个拦截器的唯一选择吗?您将如何为那些符合速率限制的请求打开休眠会话?
最后,我重写 GrailsOpenSessionInViewInterceptor
,仅当满足速率限制时才打开休眠会话。
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
}
}
然而,这对我们来说是一个临时解决方案,因为我们将来会使用一些 API 网关,例如 konghq.com。
我们想对 Grails 3 应用程序实施 API 速率限制。为此,我们使用拦截器和 redis。然而,对于每个到达 Grails 的请求,存在打开休眠会话(打开数据库连接)的问题。这是我们不能忽视的资源消耗,因为它可以通过简单的攻击轻松达到 MySQL 连接限制。
问题是强制 Grails 不为某些 urls/interceptors 打开休眠会话的最佳方法是什么。我知道像 konghq.com 这样的 API 网关,这不是我们的选择。
我也知道 GrailsOpenSessionInViewInterceptor
实施 OpenSessionInViewInterceptor
负责会话管理。那么它是覆盖这个拦截器的唯一选择吗?您将如何为那些符合速率限制的请求打开休眠会话?
最后,我重写 GrailsOpenSessionInViewInterceptor
,仅当满足速率限制时才打开休眠会话。
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
}
}
然而,这对我们来说是一个临时解决方案,因为我们将来会使用一些 API 网关,例如 konghq.com。