小编典典

使用@ControllerAdvice使简单的servlet过滤器工作

spring-boot

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

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的异常映射一起使用吗?


阅读 467

收藏
2020-05-30

共1个答案

小编典典

如java servlet规范所指定,Filter总是在Servlet调用a之前执行。现在,a
@ControllerAdvice仅对在中执行的控制器有用DispatcherServlet。因此,使用a Filter并期望a
@ControllerAdvice或在这种情况下@ExceptionHandler不会被调用。

您需要将相同的逻辑放入过滤器中(用于编写JSON响应),或者代替使用HandlerInterceptor此检查的过滤器。最简单的方法是扩展HandlerInterceptorAdapter和重写并实现该preHandle方法,并将来自过滤器的逻辑放入该方法中。

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;
    }

}
2020-05-30