带有@Preauthorize 和@@ControllerAdvice 的自定义错误消息 [英] Custom Error message with @Preauthorize and @@ControllerAdvice
问题描述
我们使用的是 spring 和 spring-security-3.2.最近我们在 RestAPIs 中添加了 @PreAuthorize 注解(之前是基于 URL 的).
We are using spring and spring-security-3.2. Recently We are adding annotations @PreAuthorize to RestAPIs(earlier it was URL based).
@PreAuthorize("hasPermission('salesorder','ViewSalesOrder')")
@RequestMapping(value = "/restapi/salesorders/", method = RequestMethod.GET)
public ModelAndView getSalesOrders(){}
我们已经有了用 - @ControllerAdvice 和自定义 PermissionEvaluator 注释的全局异常处理程序,除了错误消息外,一切正常.
We already have Global exception handler which annotated with - @ControllerAdvice and custom PermissionEvaluator in place, everything works fine except the error message.
假设某些用户正在访问 API,但没有ViewSalesOrder"权限,然后默认情况下 spring 会抛出异常访问被拒绝",但没有说明缺少哪个权限(这是我们要求提及缺少哪个权限的要求)).
Lets say some user is accessing API At moment without having 'ViewSalesOrder' permission then spring by default throws the exception 'Access is denied',but didn't tell which permission is missing (Its our requirement to mention which permission is missing).
是否有可能抛出一个包含权限名称的异常,所以最终的错误消息应该是访问被拒绝,您需要 ViewSalesOrder 权限"(这里的权限名称应该来自@PreAuthorize 注释)?
Is it possible to throw an exception which also include the permission name, so final error message should be look like "Access is denied, you need ViewSalesOrder permission"(here permission name should be from @PreAuthorize annotation)?
请注意,我们有 100 个这样的 restAPI,因此非常感谢通用解决方案.
Please note that we have 100 such restAPI in place so generic solution will be highly appreciated.
推荐答案
没有很好的方法来实现您的期望,因为 PermissionEvaluator
接口不允许您将缺少的权限与结果一起传递的评价.
此外,AccessDecisionManager
根据 AccessDecisionVoter
实例的投票决定最终授权,其中之一是 PreInvocationAuthorizationAdviceVoter
@PreAuthorize
值的评估.
长话短说,当您的自定义 PermissionEvaluator
将 false
返回给 hasPermission
调用.如您所见,无法在此流程中传播失败的原因.
There is no pretty way of achieving what you expect since PermissionEvaluator
interface doesn't let you pass the missing permission along with the result of the evaluation.
In addition, AccessDecisionManager
decides on the final authorization with respect to the votes of the AccessDecisionVoter
instances, one of which is PreInvocationAuthorizationAdviceVoter
which votes with respect to the evaluation of @PreAuthorize
value.
Long story short, PreInvocationAuthorizationAdviceVoter
votes against the request (giving the request –1 point) when your custom PermissionEvaluator
returns false
to hasPermission
call. As you see there is no way to propagate the cause of the failure in this flow.
另一方面,您可以尝试一些变通办法来实现您想要的.
一种方法是在权限检查失败时在您的自定义 PermissionEvaluator
中抛出异常.您可以使用此异常将缺少的权限传播到您的全局异常处理程序.在那里,您可以将缺少的权限作为参数传递给您的消息描述符.请注意,这将停止 AccessDecisionManager
的执行过程,这意味着不会执行后续的投票者(默认为 RoleVoter 和 AuthenticatedVoter).如果你选择走这条路,你应该小心.
另一种更安全但更笨拙的方法是实现自定义 AccessDeniedHandler 并在响应 403 之前自定义错误消息.AccessDeniedHandler
为您提供当前可以使用的 HttpServletRequest
检索请求 URI.但是,在这种情况下的坏消息是,您需要一个到权限映射的 URI 才能定位丢失的权限.
On the other hand, you may try some workarounds to achieve what you want.
One way can be to throw an exception within your custom PermissionEvaluator
when permission 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 your message descriptors as a parameter. Beware that this will halt execution process of AccessDecisionManager
which means successive voters will not be executed (defaults are RoleVoter and AuthenticatedVoter). You should be careful if you choose to go down this path.
Another safer but clumsier way can be to implement a custom AccessDeniedHandler and customize the error message before responding with 403. AccessDeniedHandler
provides you current HttpServletRequest
which can be used to retrieve the request URI. However, bad news in this case is, you need a URI to permission mapping in order to locate the missing permission.
这篇关于带有@Preauthorize 和@@ControllerAdvice 的自定义错误消息的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!