使用@ControllerAdvice 使简单的 servlet 过滤器工作 [英] Make simple servlet filter work with @ControllerAdvice
问题描述
我有一个简单的过滤器,只是为了检查请求是否包含带有静态密钥的特殊标头 - 没有用户身份验证 - 只是为了保护端点.这个想法是,如果键不匹配,则抛出一个 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 规范的规定,Filter
s 总是在调用 Servlet
之前执行.现在 @ControllerAdvice
只对在 DispatcherServlet
中执行的控制器有用.因此,使用 Filter
并期望调用 @ControllerAdvice
或在这种情况下调用 @ExceptionHandler
是不会发生的.
As specified by the java servlet specification Filter
s 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屋!