Spring mvc 在处理*@有效注释之前通知控制器方法*

Spring mvc 在处理*@有效注释之前通知控制器方法*,spring-mvc,spring-security,rate-limiting,Spring Mvc,Spring Security,Rate Limiting,我正在使用SpringMVC4.1为RESTfulWebService添加速率限制 我创建了一个可以应用于控制器方法的@RateLimited注释。Spring AOP方面拦截对这些方法的调用,并在请求过多时引发异常: @Aspect @Component @Order(Ordered.HIGHEST_PRECEDENCE) public class RateLimitingAspect { @Autowired private RateLimitService rateLim

我正在使用SpringMVC4.1为RESTfulWebService添加速率限制

我创建了一个可以应用于控制器方法的
@RateLimited
注释。Spring AOP方面拦截对这些方法的调用,并在请求过多时引发异常:

@Aspect
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class RateLimitingAspect {

    @Autowired
    private RateLimitService rateLimitService;

    @Before("execution(* com.example..*.*(.., javax.servlet.ServletRequest+, ..)) " +
            "&& @annotation(com.example.RateLimited)")
    public void wait(JoinPoint jp) throws Throwable {

        ServletRequest request =
            Arrays
                .stream(jp.getArgs())
                .filter(Objects::nonNull)
                .filter(arg -> ServletRequest.class.isAssignableFrom(arg.getClass()))
                .map(ServletRequest.class::cast)
                .findFirst()
                .get();
        String ip = request.getRemoteAddr();
        int secondsToWait = rateLimitService.secondsUntilNextAllowedAttempt(ip);
        if (secondsToWait > 0) {
          throw new TooManyRequestsException(secondsToWait);
        }
    }
除了
@RateLimited
控制器方法的参数标记为
@Valid
外,这一切都能正常工作,例如:

@RateLimited
@RequestMapping(method = RequestMethod.POST)
public HttpEntity<?> createAccount(
                           HttpServletRequest request,
                           @Valid @RequestBody CreateAccountRequestDto dto) {

...
}
@RateLimited
@RequestMapping(method=RequestMethod.POST)
公共HttpEntity创建帐户(
HttpServletRequest请求,
@有效@RequestBody CreateAccountRequestDto(dto){
...
}
问题:如果验证失败,验证器将抛出
MethodArgumentNotValidException
,该异常由
@ExceptionHandler
处理,该异常处理程序将向客户端返回错误响应,而不会在之前触发my
,因此绕过速率限制

如何以优先于参数验证的方式截获这样的web请求?


我曾想过使用Spring拦截器或普通servlet过滤器,但是它们是通过简单的url模式映射的,我需要通过GET/POST/PUT/等来区分它们。

看看是否可以为@posthrowing建议实现类似的逻辑,这些建议也将具有类似的切入点。

我最终放弃了寻找AOP解决方案的尝试,而是创建了一个Spring拦截器。拦截器
预处理
s所有请求,并监视处理程序为
@RateLimited
的请求

@Component
public class RateLimitingInterceptor extends HandlerInterceptorAdapter {

    @Autowired
    private final RateLimitService rateLimitService;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        if (HandlerMethod.class.isAssignableFrom(handler.getClass())) {
            rateLimit(request, (HandlerMethod)handler);
        }
        return super.preHandle(request, response, handler);
    }

    private void rateLimit(HttpServletRequest request, HandlerMethod handlerMethod) throws TooManyRequestsException {

        if (handlerMethod.getMethodAnnotation(RateLimited.class) != null) {
            String ip = request.getRemoteAddr();
            int secondsToWait = rateLimitService.secondsUntilNextAllowedInvocation(ip);
            if (secondsToWait > 0) {
                throw new TooManyRequestsException(secondsToWait);
            } else {
                rateLimitService.recordInvocation(ip);
            }
        }
    }
}

这是一个好问题。想知道,
@RateLimited
在做什么。在某些情况下,使用
@Valid
进行默认字段验证是痛苦的。您是否可以创建自己的
验证程序
。我可以考虑添加
标题
,以区分此特定请求。但这将为每个请求添加条件检查。我会尝试在方法层面上解决它,如果这不起作用,那么我会努力找到
拦截器