How to use the interceptor to get the value in PathVariable - spring-boot

Prompt NPE when I use the following interceptor to get
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
Map<String, String> pathVars = (Map<String, String>) request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
return HandlerInterceptor.super.preHandle(request, response, handler);
}
java.lang.NullPointerException: Cannot invoke "java.util.Map.entrySet()" because "pathVars" is null
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
Map<String, String> pathVars = (Map<String, String>) request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
return HandlerInterceptor.super.preHandle(request, response, handler);
}
java.lang.NullPointerException: Cannot invoke "java.util.Map.entrySet()" because "pathVars" is null

Related

Avoid logging Swagger Endpoints when you implement HandlerInterceptor?

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

How to return response as Json from spring filter?

In spring rest I need to send authentication error from doFilter() of my filter class. In response i need to send json with fields like status, message and errorCode. Kindly suggest how to achieve. We are not using spring boot.Below is the sample response on Authentication error
{ "responseCode":" Error code",
"responseMessage": "Some Error message",
"responseStatus":"Fail"
}
Inside doFiler(), i am validating token, if its not valid I need to send above sample response.
Assuming you have Jackson's ObjectMapper exposed as a Spring bean, you could use the following for a OncePerRequestFilter:
#Component
#RequiredArgsConstructor
public class MyFilter extends OncePerRequestFilter {
private final ObjectMapper mapper;
#Override
protected void doFilterInternal(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse,
FilterChain filterChain) throws IOException {
Map<String, Object> errorDetails = new HashMap<>();
errorDetails.put("message", "Invalid token");
httpServletResponse.setStatus(HttpStatus.FORBIDDEN.value());
httpServletResponse.setContentType(MediaType.APPLICATION_JSON_VALUE);
mapper.writeValue(httpServletResponse.getWriter(), errorDetails);
}
}
For a plain servlet Filter, the solution would be much the same:
#Component
#RequiredArgsConstructor
public class MyFilter implements Filter {
private final ObjectMapper mapper;
#Override
public void init(FilterConfig filterConfig) {
}
#Override
public void doFilter(ServletRequest servletRequest,
ServletResponse servletResponse,
FilterChain filterChain) throws IOException {
HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse;
Map<String, Object> errorDetails = new HashMap<>();
errorDetails.put("message", "Invalid token");
httpServletResponse.setStatus(HttpStatus.FORBIDDEN.value());
httpServletResponse.setContentType(MediaType.APPLICATION_JSON_VALUE);
mapper.writeValue(httpServletResponse.getWriter(), errorDetails);
}
#Override
public void destroy() {
}
}
The above examples rely on constructor injection and use Lombok's #RequiredArgsConstructor to generate a constructor that receives values for the fields marked with final.
You also could replace the Map<String, Object> for any arbitrary POJO, according to your needs.

Is there any way to call exception handler method without #enableWebMvc in Springboot

Using Exception handler i want to return new response and break the original handler response.if CustomException is thrown from filter.
i have tried below code but handler method is not called.
private boolean istest = true;
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws ServletException, IOException {
KPICounterHelper.incrementRequestCounter(request);
if(istest) {
throw new CustomException("kd ex",55);
}
chain.doFilter(request, response);
KPICounterHelper.incrementResponseCounter(request);
}
//this is handler code
#RestControllerAdvice
public class ExceptionHandler extends ResponseEntityExceptionHandler{
#org.springframework.web.bind.annotation.ExceptionHandler(value=
{CustomException.class})
public CustomException handleCustom() {
System.out.println("in handler");
return new CustomException("kd excccc", 565);
}
}
//application.properties
spring.mvc.throw-exception-if-no-handler-found=true
spring.resources.add-mappings=fals
i want to execute handler code and return response from there.
and want to execute method code after chain.doFilter()

OncePerRequestFilter I can not return HttpServletResponse custom error

I have OncePerRequestFilter:
public class ApiAuthenticationFilter extends OncePerRequestFilter {
...
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
String token = request.getHeader("X-Authorization");
if (StringUtils.isEmpty(token)) {
//return custom exception
return;
}
User user = userService.findUserByToken(token);
if (user == null) {
//return custom exception
return;
}
AuthUser authUser = new AuthUser(token, user);
SecurityContextHolder.getContext().setAuthentication(authUser);
filterChain.doFilter(request, response);
}
How can I return to client my custom exception?
I tried response.sendError(777, "Authorization token is invalid");
but client received error with status 500. I can send onli CONSTANT errors from HttpServletResponse loke this:
response.sendError(HttpServletResponse.SC_PROXY_AUTHENTICATION_REQUIRED, "Authorization token required");
But this HttpServletResponse not have all codes. For example I want send 666 error.

PreAuthorize error handling

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

Resources