我有一个简单的过滤器,仅用于检查请求是否包含带有静态密钥的特殊标头-无用户身份验证- 只是为了保护端点。这个想法是AccessForbiddenException如果键不匹配则抛出一个,然后将其映射到带有注释的类的响应@ControllerAdvice。但是我不能使它工作。我@ExceptionHandler没有被叫。
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() {} }
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的异常映射一起使用吗?
如java servlet规范所指定,Filter总是在Servlet调用a之前执行。现在,a @ControllerAdvice仅对在中执行的控制器有用DispatcherServlet。因此,使用a Filter并期望a @ControllerAdvice或在这种情况下@ExceptionHandler不会被调用。
Filter
Servlet
DispatcherServlet
您需要将相同的逻辑放入过滤器中(用于编写JSON响应),或者代替使用HandlerInterceptor此检查的过滤器。最简单的方法是扩展HandlerInterceptorAdapter和重写并实现该preHandle方法,并将来自过滤器的逻辑放入该方法中。
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; } }