Spring Security: how to intercept PageNotFound

2019-07-27 12:11发布

问题:

This seems to be an easy question but we couldn't find it anywhere on internet.

We're using Spring Security 3.2 and we want to be able to print the IP of the remote host whenever we get the spring message:

WARN  [org.springframework.web.servlet.PageNotFound] - No mapping found for HTTP request with URI [/page.bla] in DispatcherServlet with name 'XXX'.

How can we possibly do that?

回答1:

Your problem is not related to spring-security. This log message is generated in DispatcherServlet class.

You can extend org.springframework.web.servlet.DispatcherServlet and override protected void noHandlerFound(HttpServletRequest request, HttpServletResponse response) throws Exception method:

protected void noHandlerFound(HttpServletRequest request, HttpServletResponse response) throws Exception {
    if (pageNotFoundLogger.isWarnEnabled()) {
        String requestUri = urlPathHelper.getRequestUri(request);
        pageNotFoundLogger.warn("No mapping found for HTTP request with URI [" + requestUri +"] in DispatcherServlet with name '" + getServletName() + "'");
    }
    response.sendError(HttpServletResponse.SC_NOT_FOUND);
}

In this way you can customize logging message and add to it the ip address from HttpServletRequest parameter:

request.getRemoteAddr();

I'm not sure that it is a good practice.. but it should works.

Hope this helps!!



回答2:

This is only a partial answer; it solves the problem but not using spring security.

Create a filter that checks the status in the response (response.getStatus()). If the status code is one that you care about (for example 404 or HttpServletResponse.SC_NOT_FOUND) log a message with the details from the request that you want to store.



回答3:

Since Spring 4.0, if you're using @ControllerAdvice, you can also enable the fact that Spring throws a NoHandlerFoundException when it detects PageNotFound by configuring the DispatcherServlet:

@Configuration
public class ApplicationConfiguration {

    @Autowired
    void configureDispatcherServlet( DispatcherServlet dispatcherServlet ) {
        dispatcherServlet.setThrowExceptionIfNoHandlerFound(true);
    }
}

Then, in your @ControllerAdvice, you'll be able to handle this exception to return custom data:

@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler
    ResponseEntity<MyCustomError> handle(NoHandlerFoundException e) {

        return new ResponseEntity<>(new MyCustomError(), HttpStatus.NOT_FOUND);
    }
}