mvc example espaƱol ejemplo delegatingfilterproxy spring filter exception-handling spring-security spring-boot

spring - example - Haga que el trabajo de filtro de servlets sea simple con @ControllerAdvice



spring security ejemplo (2)

Tengo un filtro simple solo para verificar si una solicitud contiene un encabezado especial con clave estática, sin autenticación de usuario, solo para proteger los puntos finales. La idea es arrojar una AccessForbiddenException si la clave no coincide, que luego se asignará a la respuesta con una clase anotada con @ControllerAdvice . Sin embargo, no puedo hacer que funcione. Mi @ExceptionHandler no es llamado.

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

ExceptionController

@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) } }

Donde estoy equivocado? ¿Puede el filtro de servlet simple funcionar con el mapeo de excepción de Spring-boot?


No puede usar @ControllerAdvice , porque se llama en caso de una excepción en algún controlador, pero su ClientKeyFilter no es un @Controller .

Debe reemplazar la anotación @Controller con el @Component y simplemente establecer el cuerpo y el estado de la respuesta de esta manera:

@Component public class ClientKeyFilter implements Filter { @Value(''${CLIENT_KEY}'') String clientKey public void init(FilterConfig filterConfig) { } public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) res; String reqClientKey = request.getHeader("Client-Key"); if (!clientKey.equals(reqClientKey)) { response.sendError(HttpServletResponse.SC_FORBIDDEN, "Invalid API key"); return; } chain.doFilter(req, res); } public void destroy() { } }


Según lo especificado por la especificación del servlet de java, los Filter s se ejecutan siempre antes de que se invoque un Servlet . Ahora, un @ControllerAdvice solo es útil para el controlador, que se ejecuta dentro del DispatcherServlet . Así que usar un Filter y esperar un @ControllerAdvice o en este caso el @ExceptionHandler , que se invocará no va a suceder.

HandlerInterceptor colocar la misma lógica en el filtro (para escribir una respuesta JSON) o en lugar de un filtro usar un HandlerInterceptor que hace esta comprobación. La forma más fácil es extender HandlerInterceptorAdapter e invalidar e implementar el método preHandle y poner la lógica del filtro en ese método.

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