Rabikatha
Rabikatha

Reputation: 249

Spring boot : How could I customize the forbidden error json

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

Upvotes: 8

Views: 6939

Answers (3)

Vishal Nimavat
Vishal Nimavat

Reputation: 37

add this in your controller or ExceptionHandler :

    @ExceptionHandler(AccessDeniedException.class)
    public @ResponseBody ResponseEntity<AuthzErrorResponse> handlerAccessDeniedException(final Exception ex,
            final HttpServletRequest request, final HttpServletResponse response) {

        AuthzErrorResponse authzErrorResponse = new AuthzErrorResponse();
        authzErrorResponse.setMessage("Access denied");

        return new ResponseEntity<>(authzErrorResponse, HttpStatus.FORBIDDEN);
    }

Note:AuthzErrorResponse is my custom POJO which I want to return.

Upvotes: -1

Artem Namednev
Artem Namednev

Reputation: 417

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.

Upvotes: 5

Bharti Ladumor
Bharti Ladumor

Reputation: 1704

To display custom message i created entry point class JwtAuthenticationEntryPoint for JWT Security.

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;
@Component
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint {

    private static final Logger logger = LoggerFactory.getLogger(JwtAuthenticationEntryPoint.class);

    @Override
    public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
            AuthenticationException e) throws IOException, ServletException {
        logger.error("Responding with unauthorized error. Message - {}", e.getMessage());
        httpServletResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED,
                "Sorry, You're not authorized to access this resource.");
    }
}

And pass as entry point To security config like,

 @Configuration
 @EnableWebSecurity
 @EnableGlobalMethodSecurity(prePostEnabled = true)
 public class SecurityConfig extends WebSecurityConfigurerAdapter {

        @Autowired
        private JwtAuthenticationEntryPoint unauthorizedHandler;

        @Override
        protected void configure(HttpSecurity http) throws Exception {

            http.csrf().disable().exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
                    .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().authorizeRequests()
                    .antMatchers("auth/singIn" , "auth/singUp/")
                    .permitAll().anyRequest().authenticated();
    }
}

Or you can use @ControllerAdvice and custom exception handling to handle custom or system exception

Upvotes: 1

Related Questions