Custom error message with @Preauthorize and @@ ControllerAdvice

We use spring and spring-security-3.2. We recently add @PreAuthorize annotations to RestAPI (previously this was URL based).

@PreAuthorize("hasPermission('salesorder','ViewSalesOrder')") @RequestMapping(value = "/restapi/salesorders/", method = RequestMethod.GET) public ModelAndView getSalesOrders(){} 

We already have a global exception handler that annotates with - @ControllerAdvice and a custom PermissionEvaluator, everything works fine except for the error message.

Let's say some user accesses the API. At the moment, without the permission of "ViewSalesOrder", then spring by default throws an exception "Access is denied", but did not report which permission is missing (its requirement to indicate which permission is missing).

Is it possible to throw an exception that also includes the permission name, so the final error message should look like this: "Access is denied, you need ViewSalesOrder permission" (here the permission name should be from the @PreAuthorize annotation)?

Please note that we have 100 such restAPIs, so the overall solution will be highly appreciated.

+5
source share
1 answer

It is not possible to achieve what you expect, because the PermissionEvaluator interface does not allow you to skip the missing permission along with the evaluation result.
In addition, the AccessDecisionManager decides on the final authorization for the votes of the AccessDecisionVoter instances, one of which is PreInvocationAuthorizationAdviceVoter , which votes to evaluate @PreAuthorize .

In short, PreInvocationAuthorizationAdviceVoter votes against the request (giving the request a -1 point) when your custom PermissionEvaluator returns a call to false to hasPermission . As you can see, there is no way to propagate the cause of the failure in this thread.

On the other hand, you can try some workarounds to achieve what you want.

One way could be to throw an exception in the user PermissionEvaluator when the access check fails. You can use this exception to propagate the missing permission to your global exception handler. There you can pass the missing permission to the message descriptors as a parameter. Remember that this will stop the AccessDecisionManager execution AccessDecisionManager , which means that successive voters will not be executed (the default values ​​are RoleVoter and AuthenticatedVoter ). You must be careful if you decide to go this route.

An even safer, but clumsy way would be to implement a custom AccessDeniedHandler and configure the error message before responding to 403. AccessDeniedHandler provides you with the current HttpServletRequest , which you can use to retrieve the request URI. However, the bad news is in this case, you need a URI to map permissions to find the missing permission.

0
source

Source: https://habr.com/ru/post/1269755/


All Articles