使用@ControllerAdvice 使简单的 servlet 过滤器工作 [英] Make simple servlet filter work with @ControllerAdvice

查看:22
本文介绍了使用@ControllerAdvice 使简单的 servlet 过滤器工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个简单的过滤器,只是为了检查请求是否包含带有静态密钥的特殊标头 - 没有用户身份验证 - 只是为了保护端点.这个想法是,如果键不匹配,则抛出一个 AccessForbiddenException,然后将映射到带有 @ControllerAdvice 注释的类的响应.但是我不能让它工作.我的 @ExceptionHandler 没有被调用.

I've a simple filter just to check if a request contains a special header with static key - no user auth - just to protect endpoints. The idea is to throw an AccessForbiddenException if the key does not match which then will be mapped to response with a class annotated with @ControllerAdvice. However I can't make it work. My @ExceptionHandler isn't called.

ClientKeyFilter

import org.springframework.beans.factory.annotation.Value
import org.springframework.stereotype.Controller

import javax.servlet.*
import javax.servlet.http.HttpServletRequest

@Controller //I know that @Component might be here
public class ClientKeyFilter implements Filter {

  @Value('${CLIENT_KEY}')
  String clientKey

  public void init(FilterConfig filterConfig) {}

  public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) {
    req = (HttpServletRequest) req
    def reqClientKey = req.getHeader('Client-Key')
    if (!clientKey.equals(reqClientKey)) {
      throw new AccessForbiddenException('Invalid API key')
    }
    chain.doFilter(req, res)
  }

  public void destroy() {}
}

AccessForbiddenException

public class AccessForbiddenException extends RuntimeException {
  AccessForbiddenException(String message) {
    super(message)
  }
}

异常控制器

@ControllerAdvice
class ExceptionController {
  static final Logger logger = LoggerFactory.getLogger(ExceptionController)

  @ExceptionHandler(AccessForbiddenException)
  public ResponseEntity handleException(HttpServletRequest request, AccessForbiddenException e) {
    logger.error('Caught exception.', e)
    return new ResponseEntity<>(e.getMessage(), I_AM_A_TEAPOT)
  }
}

我错在哪里?简单的 servlet 过滤器可以与 spring-boot 的异常映射一起工作吗?

Where I'm wrong? Can simple servlet filter work with spring-boot's exception mapping?

推荐答案

按照 java servlet 规范的规定,Filters 总是在调用 Servlet 之前执行.现在 @ControllerAdvice 只对在 DispatcherServlet 中执行的控制器有用.因此,使用 Filter 并期望调用 @ControllerAdvice 或在这种情况下调用 @ExceptionHandler 是不会发生的.

As specified by the java servlet specification Filters execute always before a Servlet is invoked. Now a @ControllerAdvice is only useful for controller which are executed inside the DispatcherServlet. So using a Filter and expecting a @ControllerAdvice or in this case the @ExceptionHandler, to be invoked isn't going to happen.

您需要在过滤器中放置相同的逻辑(用于编写 JSON 响应),或者使用 HandlerInterceptor 执行此检查.最简单的方法是扩展 HandlerInterceptorAdapter 并覆盖并实现 preHandle 方法并将过滤器中的逻辑放入该方法中.

You need to either put the same logic in the filter (for writing a JSON response) or instead of a filter use a HandlerInterceptor which does this check. The easiest way is to extend the HandlerInterceptorAdapter and just override and implement the preHandle method and put the logic from the filter into that method.

public class ClientKeyInterceptor extends HandlerInterceptorAdapter {

    @Value('${CLIENT_KEY}')
    String clientKey

    @Override
    public boolean preHandle(ServletRequest req, ServletResponse res, Object handler) {
        String reqClientKey = req.getHeader('Client-Key')
        if (!clientKey.equals(reqClientKey)) {
          throw new AccessForbiddenException('Invalid API key')
        }
        return true;
    }

}

这篇关于使用@ControllerAdvice 使简单的 servlet 过滤器工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆