I have implemented Spring Boot + springfox-swagger-ui and HandlerInterceptor to log the request for my application. When I start my application following all swagger related endpoint are getting called and all those endpoint are logging into request shown below.
/webjars/springfox-swagger-ui/fonts/source-code-pro-v7-latin-300.woff2
/webjars/springfox-swagger-ui/fonts/open-sans-v15-latin-700.woff2
/webjars/springfox-swagger-ui/fonts/source-code-pro-v7-latin-300.woff2
/webjars/springfox-swagger-ui/fonts/open-sans-v15-latin-700.woff2
.....
.....
LogRequestInterceptor.java
#Slf4j
public class LogRequestInterceptor implements HandlerInterceptor {
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
ServletRequestAttributes attributes = new ServletRequestAttributes(request);
.................
.................
.................
return true;
}
#Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
printJsonReq(request, userIdentityService.getUserName(), response.getStatus(), getTime(request), handler);
}
#Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
printJsonReq(request, userIdentityService.getUserName(), response.getStatus(), getTime(request), handler);
}
}
How Can I prevent logging those requests in HandlerInterceptors preHandle and postHandle and afterCompletion methods ?
In the following link you can view an example: https://www.baeldung.com/spring-http-logging
I think that is usefull for your problem
Related
I want my prehandle method to be called.On debugging i see the control going inside ProductServiceInterceptor class but none of the methods inside are getting called
#EnableWebMvc
#Configuration
public class ProductServiceInterceptorAppConfig extends WebMvcConfigurerAdapter {
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new productServiceInterceptor()).addPathPatterns("/home/*"));
}
}
#Component
public class ProductServiceInterceptor implements HandlerInterceptor {
#Override
public boolean preHandle(
HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
return true;
}
#Override
public void postHandle(
HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {}
#Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception exception) throws Exception {}
}
I have used Spring boot 4 version project with spring security. I have tried to implement logger interceptor in my project and that is not working.
Logger Interceptor Class
#Component
public class LoggerInterceptor implements HandlerInterceptor {
#Override
public boolean preHandle(HttpServletRequest requestServlet, HttpServletResponse responseServlet, Object handler) throws Exception
{
System.out.println("MINIMAL: INTERCEPTOR PREHANDLE CALLED");
return true;
}
#Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception
{
System.out.println("MINIMAL: INTERCEPTOR POSTHANDLE CALLED");
}
#Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception exception) throws Exception
{
System.out.println("MINIMAL: INTERCEPTOR AFTERCOMPLETION CALLED");
}
}
Config class
public class InterceptorConfig implements WebMvcConfigurer {
#Autowired
LoggerInterceptor logInterceptor;
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoggerInterceptor()).addPathPatterns("/**");
}
}
I have tried the above code in simple spring boot project it is working fine, but while tried on my project it is not calling the interceptor.
Please throw some light for this.
I am working on Spring Boot Example and implemented GlobalExceptionHandler and trying to print all error messages in JSON - it's my custom method.
Also, I have ExceptionHandler there I am catching all the Exception. But is there any way to pass the exception object from ResponseEntityExceptionHandler to HandlerInterceptor?
HandlerInterceptor:
#Slf4j
public class GlobalExceptionHandler implements HandlerInterceptor {
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
............
.............
..............
return true;
}
#Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
ServletRequestAttributes attributes = (ServletRequestAttributes) request.getAttribute(REQUEST_ATTRIBUTES);
ServletRequestAttributes threadAttributes = (ServletRequestAttributes) RequestContextHolder
.getRequestAttributes();
............
.............
..............
}
#Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
if(ex != null) {
printJsonReq(request, response);
}
}
}
ExceptionHandler:
#ControllerAdvice
#Slf4j
public class ExceptionHandler extends ResponseEntityExceptionHandler{
#ExceptionHandler({ResponseStatusException.class})
protected ResponseEntity<Object> handleResStatusException(Exception e, WebRequest request, HttpServletRequest httpRequest) {
ResponseStatusException be = (ResponseStatusException) e;
ErrorResource error = ErrorResource.builder().code(AppConst.BAD_REQUEST)
.message(ExceptionUtils.getDetails(e.getCause())).build();
return handleExceptionInternal(e, error, getHeaders(), HttpStatus.BAD_REQUEST, request);
}
.........
..........
.........
}
You can set it as a request attribute in ExceptionHandler class (if you need it just to be sure you are going print log then instead of passing Exception object you can pass boolean param to not load your request object)
request.setAttribute("exception", e);
And use it in your HandlerInterceptor as
if(ex != null || request.getAttribute("exception") != null) {
printJsonReq(request, response);
}
You can configure the interceptors using WebMvcConfigurerAdapter
17.15.3 Configuring Interceptors
You can configure HandlerInterceptors or WebRequestInterceptors to be applied to all incoming requests or restricted to specific URL path patterns.
An example of registering interceptors in Java:
#Configuration
#EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new GlobalExceptionHandler());
}
}
I am implementing an interceptor for logging purposes. I know once i called the getReader method on HttpServletRequest will loose the body data, but i was experimenting. So i ran the below code, and realized the controller is never invoked (Debug point is not activated) and there was no errors.
#Component
public class IncomingRequestInterceptor extends HandlerInterceptorAdapter {
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
String requestPayload = request.getReader().lines().collect(Collectors.joining(System.lineSeparator()));
System.out.println(requestPayload);
return super.preHandle(request, response, handler);
}
#Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
super.afterCompletion(request, response, handler, ex);
}
}
And the controller
#PostMapping("/test")
public String test(#Valid #RequestBody CredentialsVo credentials) {
credentials.getUsername();
.............
return "test";
}
Filter Registration
#Configuration
public class MyConfig implements WebMvcConfigurer {
#Autowired
IncomingRequestInterceptor incomingRequestInterceptor;
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(incomingRequestInterceptor)
.addPathPatterns("/**");
}
}
if i do not call getReader() method, the controller is invoked. I was actually expecting the controller is called but i would get a null pointer or something like that.
Could anyone tell me how spring acts in this scenario ?
I'm using Spring Oauth2 and Spring Pre-post Annotations With Spring-boot
I Have a service class MyService. one of MyService methods is:
#PreAuthorize("#id.equals(authentication.principal.id)")
public SomeResponse getExampleResponse(String id){...}
can i control in some manner the json that is returned by the caller Controller?
the json that is returned by default is:
{error : "access_denied" , error_message: ".."}
I Want to be able to control the error_message param. I'm looking for something similar to:
#PreAuthorize(value ="#id.equals(authentication.principal.id)", onError ="throw new SomeException("bad params")")
public SomeResponse getExampleResponse(String id){...}
One way i thought of doing it is by Using ExceptionHandler
#ExceptionHandler(AccessDeniedException.class)
public Response handleAccessDeniedException(Exception ex, HttpServletRequest request){
...
}
but i can't control the message of the exception. and also i can't be sure that this Exception will be thrown in future releases
Spring Boot docs on error handling: http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-error-handling. One way you can control the JSON is by adding a #Bean of type ErrorAttributes.
#Bean
ErrorAttributes errorAttributes() {
return new MyErrorAttributes();
}
Implement AccessDeniedHandler
#Override
public void handle(HttpServletRequest request, HttpServletResponse response,
AccessDeniedException accessDeniedException) throws IOException, ServletException {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
try {
ObjectMapper mapper = new ObjectMapper();
SomeJsonModel jsonResponse =new SomeJsonModel();
mapper.writeValue(response.getOutputStream(), jsonResponse);
} catch (Exception e) {
throw new ServletException();
}
}
SomeJsonModel will be your own POJO/model class which you can control
And add that access denied handler in Resource Server Configuration
#Override
public void configure(HttpSecurity http) throws Exception {
http.requestMatchers()
.antMatchers(SECURED_PATTERN).and().authorizeRequests()
.antMatchers(HttpMethod.POST,SECURED_PATTERN).access(SECURED_WRITE_SCOPE)
.anyRequest().access(SECURED_READ_SCOPE).and()
.exceptionHandling().authenticationEntryPoint(newAuthExceptionEntryPoint())
.accessDeniedHandler(new MyAccessDeniedHandler());
}
It was not working for me when I implemented AccessDeniedHandler. So I created a ExceptionHandler function inside AuthenticationEntryPoint and marked the class as
#ControllerAdvice.
Please find the code below
#ControllerAdvice
#Component
public class EmrExceptionHandler implements AuthenticationEntryPoint {
private static final Logger logger = LoggerFactory.getLogger(EmrExceptionHandler.class);
#Override
public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
AuthenticationException authException) throws IOException, ServletException {
logger.error("Unauthorized error: {}", authException.getMessage());
httpServletResponse.setStatus(HttpStatus.UNAUTHORIZED.value());
httpServletResponse.getWriter().write(convertObjectToJson(new ErrorResponse(ResponseMessages.NOT_AUTHORIZED)));
}
#ExceptionHandler(value = {AccessDeniedException.class})
public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
AccessDeniedException accessDeniedException) throws IOException {
logger.error("AccessDenied error: {}", accessDeniedException.getMessage());
httpServletResponse.setStatus(HttpStatus.FORBIDDEN.value());
httpServletResponse.getWriter().write(convertObjectToJson(new ErrorResponse(ResponseMessages.NOT_PERMITTED)));
}
public String convertObjectToJson(Object object) throws JsonProcessingException {
if (object == null) {
return null;
}
ObjectMapper mapper = new ObjectMapper();
return mapper.writeValueAsString(object);
}
}