I was wondering if I could customize the following forbidden JSON error:
Actual Response
{
"timestamp": "2018-09-26T06:11:05.047+0000",
"status": 403,
"error": "Forbidden",
"message": "Access Denied",
"path": "/api/rest/hello/me"
}
Custom Response - I get it when the user request does not have permissions.
{
"code": 403,
"message": "Access denied by the system",
"status": "Failure"
}
My Web security class
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private JwtTokenProvider jwtTokenProvider;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.authorizeRequests()//
.antMatchers("/rest/hello/signin").permitAll()//
.anyRequest().authenticated();
http.apply(new JwtTokenFilterConfigurer(jwtTokenProvider));
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(12);
}
}
The most basic way of returning an error message from a REST API is to use the @ResponseStatus annotation. We can add the error message in the annotation's reason field. Although we can only return a generic error message, we can specify exception-specific error messages.
Define a class that extends the RuntimeException class. You can define the @ExceptionHandler method to handle the exceptions as shown. This method should be used for writing the Controller Advice class file. Now, use the code given below to throw the exception from the API.
You can create custom handler using the Jackson ObjectMapper
like this:
@Bean
public AccessDeniedHandler accessDeniedHandler() {
return (request, response, ex) -> {
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
ServletOutputStream out = response.getOutputStream();
new ObjectMapper().writeValue(out, new MyCustomErrorDTO());
out.flush();
};
}
And configure your HttpSecurity
like this:
http.exceptionHandling().accessDeniedHandler(accessDeniedHandler());
Also, you can try throw AuthenticationException
:
@Bean
public AuthenticationFailureHandler failureHandler() {
return (request, response, ex) -> { throw ex; };
}
And handle them in @RestControllerAdvice
:
@RestControllerAdvice
public class AdviseController {
@ExceptionHandler(AuthenticationException.class)
@ResponseStatus(HttpStatus.FORBIDDEN)
public MyCustomErrorDTO handleAuthenticationException(AuthenticationException ex) {
return new MyCustomErrorDTO();
}
}
But I'm not sure that it will work, you can check it out.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With