Accessdeniedhandler configured in spring security does not take effect

phenomenon

The following code is configured in websecurityconfigureradapter:

// Customize unauthorized and non-login exceptions
http.exceptionHandling()
        .accessDeniedHandler(new RestAccessDeniedHandler())
        .authenticationEntryPoint(new RestAuthenticationEntryPoint());

The @preauthorize annotation is added to the rest interface of the controller layer:

@PreAuthorize(value = "hasAuthority('Users.Update')")
@GetMapping("/hello")
public ResponseEntity<?> hello(@RequestParam(value = "name", required = false, defaultValue = "Tom") String name) {
    return ResponseEntity.ok(RestResponse.buildResponse("Hi: " + name));
}

The provider interface/Hello reports a server 500 error and does not execute the accessdeniedhandler we set to handle exceptions with insufficient permissions.

reason

The @preauthorize annotated exception throws an accessdeniedexception, which will not be caught by the accessdeniedhandler, but by the global exception. Example code for global exception handling accessdeniedexception:

@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(Exception.class)
    public ResponseEntity<RestResponse<Object>> handleException(Exception exception) {
        String message = exception.getLocalizedMessage();
        log.error("Exception: {}", message, exception);
        HttpStatus httpStatus = HttpStatus.INTERNAL_SERVER_ERROR;
        if (exception instanceof BadCredentialsException) {
            httpStatus = HttpStatus.UNAUTHORIZED;
        }
        if (exception instanceof HttpRequestMethodNotSupportedException) {
            httpStatus = HttpStatus.METHOD_NOT_ALLOWED;
        }
        return RestResponse.buildError(httpStatus, message);
    }

    @ExceptionHandler(CommonException.class)
    public ResponseEntity<RestResponse<Object>> handleException(CommonException exception) {
        String message = exception.getLocalizedMessage();
        log.error("CommonException:{}", message);
        return RestResponse.buildError(exception.getBusinessStatus(), message);
    }

    @ExceptionHandler(AccessDeniedException.class)
    public ResponseEntity<RestResponse<Object>> handleException(AccessDeniedException exception) {
        String message = exception.getLocalizedMessage();
        log.error("AccessDeniedException: {}", message);
        return RestResponse.buildError(HttpStatus.FORBIDDEN, Forbidden);
    }

}

If it needs to be captured and processed by accessdeniedhandler, you need to write the code of websecurityconfigureradapter as follows:

http.cors().and()
        .authorizeRequests().antMatchers("/hello0").permitAll()
        // Note that hasRole, hasAuthority will call the set accessDeniedHandler method if an exception occurs.
        .antMatchers("/hello").hasAuthority("Users.Update")
        .anyRequest().authenticated();
        
// Customize unauthorized and non-login exceptions
http.exceptionHandling()
        .accessDeniedHandler(new RestAccessDeniedHandler())
        .authenticationEntryPoint(new RestAuthenticationEntryPoint());

Similar Posts: