Gökhan Öner (Migrated from SEC-3104) said:

@PreAuthorize, @PostAuthorize, @Secured annotation can have a parameter to point custom message property in order to set detailed & more user friendly exception messages.

This could also be done by providing a param. to define an class name that extends AccessDeniedException to raise to you let users handle the rest.

This way, while processing complex rules like

@PreAuthorize("record.createuser != authentication.getName()")

We can get a defined error like

"You cannot process a record that you created."" etc. insted of "Access is denied"

Comment From: marcusdacoregio

I wonder what are the advantages of doing this instead of calling a custom bean that does the logic:

@RestController
class HelloController {

    @GetMapping("/hello")
    @PreAuthorize("@authorization.check()")
    public String hello() {
        return "hello";
    }

    @ExceptionHandler(CustomAccessDenied.class)
    public ResponseEntity<String> handleCustomAccessDenied(CustomAccessDenied ex) {
        return ResponseEntity.status(403).body(ex.getMessage());
    }

}

@Component
public class Authorization {

    public boolean check() {
        throw new CustomAccessDenied();
    }

}

static class CustomAccessDenied extends AccessDeniedException {

    public CustomAccessDenied() {
        super("CustomAccessDenied");
    }
}

Comment From: jzheaux

As for 6.3, this can be done in the following way:

Option 1

Publish a MethodAuthorizationDeniedHandler:

@Component
public class CustomException implements MethodAuthorizationDeniedHandler {
    @Override 
    Object handleDeniedInvocation(MethodInvocation invocation, AuthorizationResult result) {
        throw new AuthorizationDeniedException("my custom message");
    }
}

And then use it in an annotation on the method like so:

@PreAuthorize(...)
@HandleAuthorizationDenied(handlerClass=CustomException.class)
public String method() { ... }

Option 2

Or, you can use Spring's meta-annotation support to make this more flexible. Define a new annotation:

...
@HandleAuthorizationDenied(handlerClass=CustomException.class)
public @interface CustomErrorMessage {
    String value() default "access is denied";
}

Publish a MethodAuthorizationDeniedHandler:

@Component
public class CustomException implements MethodAuthorizationDeniedHandler {
    @Override 
    Object handleDeniedInvocation(MethodInvocation invocation, AuthorizationResult result) {
        String message = AnnotationUtils.findAnnotation(invocation.getMethod(), CustomErrorMessage.class).value();
        throw new AuthorizationDeniedException(message);
    }
}

And then use:

@PreAuthorize(...)
@CustomMessage("my custom message")
public String method() { ... }