6

Ho un semplice filtro solo per verificare se una richiesta contiene un'intestazione speciale con chiave statica - nessuna autorizzazione utente - solo per proteggere gli endpoint. L'idea è di lanciare un AccessForbiddenException se la chiave non corrisponde a quella che verrà mappata alla risposta con una classe annotata con @ControllerAdvice. Tuttavia non posso farlo funzionare. Il mio @ExceptionHandler non viene chiamato.Crea un semplice filtro servlet con @ControllerAdvice

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

Dove mi sbaglio? Un semplice filtro servlet funziona con la mappatura delle eccezioni di spring-boot?

+0

Ciò non accadrà mai per un filtro. '@ ControllerAdvice' è utile solo per le richieste che raggiungono' DispatcherServlet', 'Filter's viene sempre eseguito prima. O metti quella logica nel filtro o invece di un filtro usa un 'HandlerInterceptor'. –

+0

@ M.Deinum, ho finalmente usato 'HandlerInterceptor'. Se desideri aggiungerlo come risposta, sarò felice di accettarlo. – Opal

risposta

3

Come specificato dalla specifica servlet Java Filter s eseguire sempre prima di un Servlet viene richiamato. Ora un @ControllerAdvice è utile solo per il controller che viene eseguito all'interno di DispatcherServlet. Quindi, usando un Filter e aspettandoci un @ControllerAdvice o in questo caso lo @ExceptionHandler, da invocare, non accadrà.

È necessario inserire la stessa logica nel filtro (per scrivere una risposta JSON) o invece di un filtro utilizzare uno HandlerInterceptor che esegue questo controllo. Il modo più semplice consiste nell'estendere lo HandlerInterceptorAdapter e solo sovrascrivere e implementare il metodo preHandle e inserire la logica dal filtro in tale metodo.

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

} 
+0

Può essere cambiato da quando hai postato la risposta, ma la firma ora è: 'preHandle booleano pubblico (richiesta HttpServletRequest, risposta HttpServletResponse, gestore oggetti) genera Exception' – Zakaria

4

Non è possibile utilizzare @ControllerAdvice, perché viene chiamato in caso di un'eccezione in alcuni controller, ma lo ClientKeyFilter non è un @Controller.

è necessario sostituire il @Controller annotazioni con il @Component e il corpo di risposta appena impostato e lo stato in questo modo:

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